认证成功后如何调用Controller的login方法返回响应
Alright, let's break down why your login() controller method isn't firing and how to adjust your setup to make it work as expected:
问题根源
Your MobileAuthenticationFilter is intercepting the /api/users/login request first. By default, once authentication succeeds in this filter, Spring Security will use the configured AuthenticationSuccessHandler to handle the response directly—it doesn't forward the request to the DispatcherServlet (and thus your controller). That's why your controller method never gets called.
具体实现方案
Here's how to modify your code to let the request flow to your controller after successful authentication:
Adjust the Authentication Success Handler in your Filter Bean
Remove your current success handler logic that prints the request, and instead configure it to forward the request to your controller after storing the authentication in the security context.@Bean public MobileAuthenticationFilter mobileAuthenticationFilter(ObjectMapper objectMapper) throws Exception { MobileAuthenticationFilter mobileAuthenticationFilter = new MobileAuthenticationFilter(objectMapper); mobileAuthenticationFilter.setAuthenticationManager(authenticationManager()); mobileAuthenticationFilter.setAuthenticationSuccessHandler((request, response, authentication) -> { // Store the authenticated user in SecurityContext so the controller can access it SecurityContextHolder.getContext().setAuthentication(authentication); // Forward the request to the controller's login endpoint request.getRequestDispatcher(request.getRequestURI()).forward(request, response); }); return mobileAuthenticationFilter; }Verify your Controller Method works with Authenticated Context
Your existinglogin()method uses aPrincipal principalparameter—once the authentication is stored inSecurityContextHolder, Spring will automatically inject the authenticatedAuthenticationobject as thePrincipal, so this will work seamlessly. You can even cast it toUsernamePasswordAuthenticationTokenif you need specific user details:public TokenResponse login(@RequestBody LoginUserRequest loginUserRequest, Principal principal) { // Optional: Get authenticated user details UsernamePasswordAuthenticationToken authToken = (UsernamePasswordAuthenticationToken) principal; String username = authToken.getName(); // Return your token response as before return new TokenResponse().setAccessToken("token"); }Ensure Security Config Doesn't Block the Forwarded Request
Your existingWebSecurityConfigurerAdaptersetup already permits access to/api/users/login, so no changes are needed here. The forwarded request will bypass further authentication checks because theSecurityContextalready contains a valid authentication.Optional: Clean Up the Filter's Request Parsing
Your currentattemptAuthenticationmethod manually reads the request body with aBufferedReader—you can simplify this using theObjectMapperdirectly with the request input stream:@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { LoginUserRequest loginUserRequest = objectMapper.readValue(request.getInputStream(), LoginUserRequest.class); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginUserRequest.getLogin(), loginUserRequest.getPassword()); return getAuthenticationManager().authenticate(token); } catch (IOException e) { throw new BadCredentialsException("Failed to parse login request body", e); } }
How it works now
When a login request comes in:
MobileAuthenticationFilterintercepts it, parses the credentials, and authenticates the user.- On success, it stores the authentication in
SecurityContextHolderand forwards the request to your controller's/api/users/loginendpoint. - The controller method runs, uses the authenticated principal if needed, and returns the
TokenResponsefollowing your annotation-based response rules.
内容的提问来源于stack exchange,提问作者Piotr Olaszewski

