Spring custom authentication filter and provider not calling controller method

I am trying to implement custom authentication logic with the latest version of Spring Boot, Web and Security, but I am struggling with some problems. I often tested many solutions in similar questions / tutorials or realized what was really going on.

I am creating a REST application with verification without authentication, i.e. there is a REST endpoint (/ web / auth / login) that expects a username and password and returns a string token, which is then used by all other REST endpoints (/ api / **) to identify the user. I need to implement a custom solution, as authentication in the future will become more complex, and I would like to understand the basics of Spring Security.

To achieve token authentication, I create a custom filter and provider:

Filter:

public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public TokenAuthenticationFilter() { super(new AntPathRequestMatcher("/api/**", "GET")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { String token = request.getParameter("token"); if (token == null || token.length() == 0) { throw new BadCredentialsException("Missing token"); } UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(token, null); return getAuthenticationManager().authenticate(authenticationToken); } } 

The supplier:

 @Component public class TokenAuthenticationProvider implements AuthenticationProvider { @Autowired private AuthenticationTokenManager tokenManager; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String token = (String)authentication.getPrincipal(); return tokenManager.getAuthenticationByToken(token); } @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.equals(authentication); } } 

Configuration:

 @EnableWebSecurity @Order(1) public class TokenAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private TokenAuthenticationProvider authProvider; @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/api/**") .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().addFilterBefore(authenticationFilter(), BasicAuthenticationFilter.class); } @Bean public TokenAuthenticationFilter authenticationFilter() throws Exception { TokenAuthenticationFilter tokenProcessingFilter = new TokenAuthenticationFilter(); tokenProcessingFilter.setAuthenticationManager(authenticationManager()); return tokenProcessingFilter; } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } } 

AuthenticationTokenManager used by the provider (as well as during the login process):

 @Component public class AuthenticationTokenManager { private Map<String, AuthenticationToken> tokens; public AuthenticationTokenManager() { tokens = new HashMap<>(); } private String generateToken(AuthenticationToken authentication) { return UUID.randomUUID().toString(); } public String addAuthentication(AuthenticationToken authentication) { String token = generateToken(authentication); tokens.put(token, authentication); return token; } public AuthenticationToken getAuthenticationByToken(String token) { return tokens.get(token); } 

}

What happens: I add a valid token in the request to "/ api / bla" (which is a REST controller returning some Json). Filter and provider are both called. Problem , the browser is redirected to "/" instead of calling the requested REST controller method. This is similar to SavedRequestAwareAuthenticationSuccessHandler, but why is this handler used?

I tried

  • to implement an empty success handler, leaving the status code 200 and still not calling the controller.
  • perform authentication in a simple GenericFilterBean and set the authentication object through SecurityContextHolder.getContext (). setAuthentication, which results in a Bad Credentials page error.

I would like to understand why my controller is not being called after I authenticated the token. In addition, is there a β€œSpring” method for storing a token instead of storing it on a map, for example, for a custom implementation of SecurityContextRepository?

I really appreciate any hint!

+5
source share
1 answer

Maybe a little late, but I had the same problem and add:

 @Override protected void successfulAuthentication( final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authResult) throws IOException, ServletException { chain.doFilter(request, response); } 

to my implementation of AbstractAuthenticationProcessingFilter did the trick.

0
source

All Articles