【发布时间】:2020-12-08 22:23:48
【问题描述】:
我正在尝试使用 spring security 并遇到了一个奇怪的行为。 我的想法是创建一个基于 JWT(或 JWS)令牌对请求进行身份验证的安全过滤器:
public class JWTokenFilter extends AbstractAuthenticationProcessingFilter {
public JWTokenFilter(AuthenticationManager authenticationManager) {
super("/**"); //doesn't have any effect, every request still gets considered by this filter
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token)) {
throw new TokenException("Token is empty");
}
var authentication = determineAuthentication(token.replace("Bearer","").trim());
//the AbstractAuthenticationProcessingFilter fills the Security context
return this.getAuthenticationManager().authenticate(authentication);
}
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
System.out.println("Asked for "+request.getRequestURI());
return request.getHeader("Authorization") != null;
}
private TokenAuthentication<UserInfo> determineAuthentication(String token) {
var split = token.split("\\.");
if (split.length < 2 || split.length > 3) {
throw new TokenException("Token malformed");
}
if (split.length == 2){
return new JWTAuthentication<>(token);
}else {
return new JWSAuthentication<>(token);
}
}
}
我有 3 个 @RestController 类,它们的路径已映射:
@RequestMapping("/admin")@RequestMapping("/all")@RequestMapping("/anon")
除此之外,我还有以下安全配置:
@Configuration
@Order(98)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/all/**","/anon/**")
.and()
.authorizeRequests().antMatchers("/all/**").permitAll()
.and()
.authorizeRequests().antMatchers("/anon/**").anonymous();
}
@Override
public void configure(WebSecurity web) {
web.ignoring().mvcMatchers("/webjars/**", "/css/**");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Configuration
@Order(99)
public static class TokenSecurityConfig extends WebSecurityConfigurerAdapter{
@Lazy
@Autowired
private JWTokenFilter tokenFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //having /admin/** or /** makes no difference
.anyRequest().authenticated()
.and().addFilterBefore(tokenFilter,ExceptionTranslationFilter.class);//put this filter near the end of the chain
}
@Bean
public JWTokenFilter tokenFilter(JWTokenAuthenticationProvider jwTokenAuthenticationProvider,JWSTokenAuthenticationProvider jwsTokenAuthenticationProvider){
var list = new ArrayList<AuthenticationProvider>();
list.add(jwsTokenAuthenticationProvider);
list.add(jwTokenAuthenticationProvider);
ProviderManager manager = new ProviderManager(list);
return new JWTokenFilter(manager);
}
}
}
从这里的配置我们可以看到有2个SecurityFilterChans(不包括/webjars和/css):
- 匹配
"/all/**"和"/anon/**"REST 路由的所有请求 - 匹配任何请求
由于 1. 链的 @Order(98) 低于 2. @Order(99),这意味着 1. 链 将首先考虑,如下所示调试器,
如果传入请求如下所示匹配:
curl --request GET \
--url http://localhost:8080/all/hello \
现在我遇到的是 JWTokenFilter 方法 boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) 无论请求路径如何,都会被调用!
在控制台输出中,我可以找到Asked for /all/hello。
编辑:
我的spring boot版本是2.3.6.RELEASE
我的问题是:
为什么JWTokenFIlter 甚至被问到它是否应该对路径与SecurityFilterChain 不匹配的请求进行身份验证?
【问题讨论】:
标签: spring-boot spring-mvc spring-security