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
答案 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/**"
时,才会触发您的过滤器。