My authenticationTokenFilterBean is getting called on non protected endpoints

时间:2019-04-16 23:47:47

标签: spring spring-security jwt

Context: I am building an API using spring, and spring security to protect my endpoints.

What I've tried: I create a WebSecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig : WebSecurityConfigurerAdapter() {

    @Autowired
    private lateinit var unauthorizedHandler: JwtAuthenticationEntryPoint

    @Qualifier("jwtUserDetailsServiceImpl")
    @Autowired
    private lateinit var userDetailsService: UserDetailsService

    @Autowired
    @Throws(Exception::class)
    fun configureAuthentication(authenticationManagerBuilder: AuthenticationManagerBuilder) {
        authenticationManagerBuilder.userDetailsService<UserDetailsService>(this.userDetailsService).passwordEncoder(passwordEncoder())
    }

    @Bean
    @Throws(Exception::class)
    fun customAuthenticationManager(): AuthenticationManager {
        return authenticationManager()
    }

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    @Bean
    @Throws(Exception::class)
    fun authenticationTokenFilterBean(): JwtAuthenticationTokenFilter {
        return JwtAuthenticationTokenFilter()
    }

    @Throws(Exception::class)
    override fun configure(httpSecurity: HttpSecurity) {
        httpSecurity.csrf().disable()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/api/user/**").permitAll()
                .antMatchers(
                        HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter::class.java)
        httpSecurity.headers().cacheControl()
    }
}

My problem: My authenticationTokenFilterBean is getting called on endpoint started by api/user since I am doing ("/api/user/**").permitAll() is this supposed to happen? Because this is calling my JwtAuthenticationTokenFilter (above) and my authToken is always null because I don't pass anything in the Authorization header(since this is an account creation and thats why I put the permitAll in this endpoint ("/api/user/**").permitAll()

class JwtAuthenticationTokenFilter : OncePerRequestFilter() {

    @Qualifier("jwtUserDetailsServiceImpl")
    @Autowired
    private lateinit var userDetailsService: UserDetailsService

    @Autowired
    private lateinit var jwtTokenUtil: JwtTokenUtil

    @Throws(ServletException::class, IOException::class)
    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
        val authToken = request.getHeader("Authorization")
        val username = jwtTokenUtil.getUsernameFromToken(authToken)

        if (username != null && SecurityContextHolder.getContext().authentication == null) {
            val userDetails = this.userDetailsService.loadUserByUsername(username)
            if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                val authentication = UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.authorities)
                authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
                logger.info("authenticated user $username, setting security context")
                SecurityContextHolder.getContext().authentication = authentication
            }
        }
        chain.doFilter(request, response)
    }
}

Objective: Can someone help me discover if its normal that my authenticationTokenFilterBean is being called on non-protected API. And if it is explain how can I do it. Thanks

1 个答案:

答案 0 :(得分:1)

对未受保护的端点的请求仍将通过整个过滤器链,其中包括您的过滤器。 permitAll()意味着FilterSecurityInterceptor将允许未经身份验证的用户访问端点,但不影响请求通过的筛选器。

.antMatchers("/api/auth/**").permitAll() //allow unauthenticated users

如果您希望过滤器仅应用于某些请求,则可以添加RequestMatcher,该过滤器在过滤器的构造函数中初始化,并且具有一定的匹配路径。例如,new NegatedRequestMatcher(new AntPathRequestMatcher("/api/user/**"))将匹配除不受保护的端点之外的任何路径。然后在doFilterInternal()中,您可以执行以下操作:

if(!requestMatcher.matches(request)) {
    chain.doFilter(request, response);
    return;
}
// ... the rest of your logic

现在,仅当请求不是您期望的"/api/user/**"时,才会触发您的过滤器。