lenve/vhr · warning · AuthenticationServiceException
Authentication method not supported: {request.getMethod()}
Error message
Authentication method not supported: {request.getMethod()} What it means
Thrown by the overridden UsernamePasswordAuthenticationFilter.attemptAuthentication when the HTTP method of the incoming request is not POST. UsernamePasswordAuthenticationFilter is contract-bound to POST form/json credentials; LoginFilter preserves that contract and rejects GET (or any other verb) immediately with an AuthenticationServiceException before parsing the body or verifying the captcha.
Source
Thrown at vhr/vhrserver/vhr-web/src/main/java/org/javaboy/vhr/config/LoginFilter.java:34
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @作者 江南一点雨
* @微信公众号 江南一点雨
* @网站 http://www.javaboy.org
* @微信 a_java_boy
* @GitHub https://github.com/lenve
* @Gitee https://gitee.com/lenve
*/
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
SessionRegistry sessionRegistry;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String verify_code = (String) request.getSession().getAttribute("verify_code");
if (request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().contains(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
Map<String, String> loginData = new HashMap<>();
try {
loginData = new ObjectMapper().readValue(request.getInputStream(), Map.class);
} catch (IOException e) {
}finally {
String code = loginData.get("code");
checkCode(response, code, verify_code);
}
String username = loginData.get(getUsernameParameter());
String password = loginData.get(getPasswordParameter());
if (username == null) {
username = "";
}
if (password == null) {View on GitHub (pinned to 03abbd35af)
Solutions
- Change the login request to POST: in the front-end use axios.post('/doLogin', data) or fetch(url, { method: 'POST', body: ... }).
- Ensure the form's method attribute is 'post' (method='post') if using a traditional HTML form submit to the login URL.
- If a reverse proxy is in front, confirm it preserves the HTTP method and is not rewriting POST to GET (check X-Forwarded-* and proxy config).
- Allow CORS preflight by ensuring the OPTIONS method is permitted/short-circuited before reaching this filter (configure CORS filter ordering).
- Verify the configured loginProcessingUrl matches the URL the client targets so the POST actually lands here.
Example fix
// before
axios.get('/doLogin', { params: { username, password } });
// after
axios.post('/doLogin', { username, password, code }); Defensive patterns
Strategy: validation
Validate before calling
// Front-end: assert the method before sending.
function login(payload) {
// UsernamePasswordAuthenticationFilter requires POST
return axios.post('/doLogin', payload); // never axios.get here
} Type guard
// Java: a guard inside the filter to give a cleaner message (optional; the throw is correct).
String method = request.getMethod();
if (!"POST".equalsIgnoreCase(method)) {
response.setStatus(405);
response.setHeader("Allow", "POST");
return; // or keep the existing throw
} Try / catch
// Not typically caught per-request; configure the framework instead.
// Ensure the loginProcessingUrl is only reachable via POST by mapping it on POST only,
// and let AuthenticationServiceException flow to the failure handler:
// http.formLogin().loginProcessingUrl("/doLogin") // Spring binds POST by default
// Add a 405 fallback for non-POST so clients get a clear signal:
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
AuthenticationException ex) {
if (ex instanceof AuthenticationServiceException
&& ex.getMessage().startsWith("Authentication method not supported")) {
resp.setStatus(405);
}
} Prevention
- Pin the login call to POST in a single front-end service method and reuse it — never hand-write the login request.
- Document the login endpoint as POST-only in the API contract.
- Add an OPTIONS/CORS preflight allowance so preflight never reaches this filter.
- Write an integration test asserting GET on the login URL returns 405/401, not 200.
When it happens
Trigger: A GET request (e.g., a browser navigation, a link, or a misconfigured fetch) hits the configured login-processing URL (default /doLogin or /login). The first guard in attemptAuthentication compares request.getMethod() to 'POST', and on mismatch throws AuthenticationServiceException with the actual method name interpolated into the message.
Common situations: Front-end developer used axios.get or fetch without method:'POST' for the login call; a browser pre-filled the login URL into the address bar and someone hit Enter; a redirect from an intercepting filter converted the POST to GET; a proxy/load balancer rewrites the method; Spring Security's loginProcessingUrl was triggered by a navigation rather than a form action; CORS preflight (OPTIONS) reached this filter.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of lenve/vhr@03abbd35af (2026-08-14).
Data as JSON: /api/errors/1dcbcacdc305b2f0.
Report an issue: GitHub.