Spring security filter not firing up

前端 未结 2 1606
孤城傲影
孤城傲影 2020-12-22 02:54

My authentication filters are not firing up under request.

I have 2 security configurations, one for the login endpoint only, authenticating with the Authentic

相关标签:
2条回答
  • 2020-12-22 03:19

    Your filters extend UsernamePasswordAuthenticationFilter and this filter by default is only applied for URL /login, see UsernamePasswordAuthenticationFilter:

    This filter by default responds to the URL /login.

    If you want to change the default to another URL, see AbstractAuthenticationProcessingFilter#setFilterProcessesUrl:

    Sets the URL that determines if authentication is required

    Your modified code:

    public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
        AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter();
        authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
        authenticationFromCredentialsFilter.setFilterProcessesUrl("/api/users/login");
        return authenticationFromCredentialsFilter;
    }
    

    If you want to use a pattern, see AbstractAuthenticationProcessingFilter:

    This filter will intercept a request and attempt to perform authentication from that request if the request matches the setRequiresAuthenticationRequestMatcher(RequestMatcher).

    Your modified code:

    public AuthenticationFromTokenFilter authenticationFromTokenFilter() throws Exception {
        AuthenticationFromTokenFilter authenticationFromTokenFilter= new AuthenticationFromTokenFilter();
        authenticationFromTokenFilter.setAuthenticationManager(authenticationManagerBean());
        authenticationFromTokenFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/**");
        return authenticationFromTokenFilter;
    }
    
    0 讨论(0)
  • 2020-12-22 03:25

    I could finally have the filters fire up and each for their own requests under a Spring Boot 2 environment.

    The credentials filter fires up upon a login request to the /users/login endpoint.

    The token filter fires up upon any request except the login request.

    To assign a url pattern to a filter, the filter had to extend the AbstractAuthenticationProcessingFilter class. And the two filters extend that class. The pattern is specified in their constructor.

    The credentials filter is:

    public class AuthenticationFromCredentialsFilter extends AbstractAuthenticationProcessingFilter {
    
        @Autowired
        private TokenAuthenticationService tokenAuthenticationService;
    
        @Autowired
        CredentialsService credentialsService;
    
        public AuthenticationFromCredentialsFilter(final RequestMatcher requestMatcher) {
            super(requestMatcher);
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
                throws AuthenticationException {
            try {
                CredentialsResource credentialsResource = new ObjectMapper().readValue(req.getInputStream(),
                        CredentialsResource.class);
                return credentialsService.authenticate(credentialsResource);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                Authentication authentication) throws IOException, ServletException {
            tokenAuthenticationService.addTokenToResponseHeader(response, authentication);
        }
    
    }
    

    Note that on successful authentication, the filter chain is not pursued, that is there is no such call to filterChain.doFilter(httpRequest, httpResponse); because there is no need to hit a controller endpoint, since the response is already sent back with the token.

    It is explicitly instantiated with a @Bean annotation so as to specify the matcher pattern:

    @Bean
    public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
        AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter(new AntPathRequestMatcher("/users/login", RequestMethod.POST.name()));
        authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
        return authenticationFromCredentialsFilter;
    }
    

    The token filter is:

    public class AuthenticationFromTokenFilter extends AbstractAuthenticationProcessingFilter {
    
        @Autowired
        private TokenAuthenticationService tokenAuthenticationService;
    
        public AuthenticationFromTokenFilter(final RequestMatcher requestMatcher) {
            super(requestMatcher);
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
                throws AuthenticationException {
            return tokenAuthenticationService.authenticate(request);
        }
    
        @Override
        protected void successfulAuthentication(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
                FilterChain filterChain, Authentication authResult) throws IOException, ServletException {
            filterChain.doFilter(httpRequest, httpResponse);
        }
    
    }
    

    It is explicitly instantiated with a @Bean annotation so as to specify the matcher pattern:

    @Bean
    public AuthenticationFromTokenFilter authenticationFromTokenFilter() throws Exception {
        AuthenticationFromTokenFilter authenticationFromTokenFilter = new AuthenticationFromTokenFilter(new NegatedRequestMatcher(new AntPathRequestMatcher("/users/login", RequestMethod.POST.name())));
        authenticationFromTokenFilter.setAuthenticationManager(authenticationManagerBean());
        return authenticationFromTokenFilter;
    }
    

    Contrary to the previous credentials filter, this filter needs to be explicitly specified in the configuration:

    http
    .addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class)
    

    To avoid this filter being fired up twice in the filters chain, a bean instructs Spring Boot not to automatically inject it:

    @Bean
    FilterRegistrationBean<AuthenticationFromTokenFilter> disableAutoRegistration(final AuthenticationFromTokenFilter filter) {
        final FilterRegistrationBean<AuthenticationFromTokenFilter> registration = new FilterRegistrationBean<AuthenticationFromTokenFilter>(filter);
        registration.setEnabled(false);
        return registration;
    }
    

    Note that on successful authentication, the filter chain is pursued, that is there is a call to filterChain.doFilter(httpRequest, httpResponse); because there is a need to hit a controller endpoint, after successful authentication.

    The full configuration is:

    @ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security",
    "com.thalasoft.user.rest.service", "com.thalasoft.user.rest.filter" })
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
    
        @Autowired
        private SimpleCORSFilter simpleCORSFilter;
    
        @Autowired
        AuthenticationFromTokenFilter authenticationFromTokenFilter;
    
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Bean
        public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
            AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter(new AntPathRequestMatcher("/users/login", RequestMethod.POST.name()));
            authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
            return authenticationFromCredentialsFilter;
        }
    
        @Bean
        public AuthenticationFromTokenFilter authenticationFromTokenFilter() throws Exception {
            AuthenticationFromTokenFilter authenticationFromTokenFilter = new AuthenticationFromTokenFilter(new NegatedRequestMatcher(new AntPathRequestMatcher("/users/login", RequestMethod.POST.name())));
            authenticationFromTokenFilter.setAuthenticationManager(authenticationManagerBean());
            return authenticationFromTokenFilter;
        }
    
        @Bean
        FilterRegistrationBean<AuthenticationFromTokenFilter> disableAutoRegistration(final AuthenticationFromTokenFilter filter) {
            final FilterRegistrationBean<AuthenticationFromTokenFilter> registration = new FilterRegistrationBean<AuthenticationFromTokenFilter>(filter);
            registration.setEnabled(false);
            return registration;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors();
    
            http
            .csrf().disable()
            .formLogin().disable()
            .httpBasic().disable()
            .logout().disable();
    
            http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
    
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    
            http.addFilterBefore(simpleCORSFilter, ChannelProcessingFilter.class);
    
            http
            .addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/", "/error").permitAll()
            .antMatchers("/users/login").permitAll()
            .antMatchers("/admin/**").hasRole(UserDomainConstants.ROLE_ADMIN)
            .anyRequest().authenticated();
        }
    
    }
    

    Also, note that the is not being used at all in this Spring Boot configuration:

    @Component
    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
        @Autowired
        CredentialsService credentialsService;
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            return credentialsService.authenticate(authentication);
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
        }
    
    }
    

    I wonder where it could fit and how it could replace the credentials filter... but that is another story.

    0 讨论(0)
提交回复
热议问题