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

  1. Change the login request to POST: in the front-end use axios.post('/doLogin', data) or fetch(url, { method: 'POST', body: ... }).
  2. Ensure the form's method attribute is 'post' (method='post') if using a traditional HTML form submit to the login URL.
  3. 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).
  4. Allow CORS preflight by ensuring the OPTIONS method is permitted/short-circuited before reaching this filter (configure CORS filter ordering).
  5. 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

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

Related errors


AI-assisted analysis of lenve/vhr@03abbd35af (2026-08-14). Data as JSON: /api/errors/1dcbcacdc305b2f0. Report an issue: GitHub.