记录使用springsecurity整合jwt时静态资源访问及过滤器顺序异常
首先晒出我的security错误配置
http.addFilterBefore(new JwtLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
// 访问控制时登录状态检查过滤器
.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
//此处需要注意 自定义资源权限认证过滤器需要在异常处理过滤器之后 因为资源权限认证过滤器一般位于登录认证的最后 如果异常过滤器在资源认证过滤器后 将不会生效
.addFilterAfter(getMyFilterSecurityInterceptor(), ExceptionTranslationFilter.class)
.exceptionHandling().accessDeniedHandler(new MyAccessDeineHandler()).authenticationEntryPoint(new MyAuthenticationEntryPoint())
.and()
// 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
.cors().and().csrf().disable()
.headers().frameOptions().disable();
// 退出登录处理器
http.logout().logoutUrl("/loginout").logoutSuccessHandler(new MyLoginOutSuccessHandler());
//禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
.authorizeRequests()
// 跨域预检请求
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 登录URL
.antMatchers("/login").permitAll()
.antMatchers("/index.html").permitAll()
.antMatchers("/static/**").permitAll()
.antMatchers("/favicon.ico").permitAll()
// swagger
.antMatchers("/swagger**/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/v2/**").permitAll()
// 其他所有请求需要身份认证
.anyRequest().authenticated();
首先 乍一看我这配置没什么问题,登录及权限测试都没啥问题。
但是
问题一:退出登录传递到指定处理类时,authentication值为空,无法退出登录对redis中token做退出处理
原因:
因为使用jwt的原因 我自定义jwt token验证过滤器JwtAuthenticationFilter
(看我上面的配置),并将此过滤器置于UsernamePasswordAuthenticationFilter
之前。JwtAuthenticationFilter
中我用于验证token,并且组装authentication
放入SecurityContextHolder
中。经过我断点得知,logoutFilter
过滤器位于我自定义过滤器之前,所以不论退出登录多少次,首先经过的就是logoutFilter
,而不会到达JwtAuthenticationFilter
无法组装authentication
信息。
问题二:当我把前端vue项目打包到我的项目中时,无法访问到页面
原因:
上文中配置了静态资源过滤,但是并没有起到作用
因为我的自定义过滤器中有token验证过滤器,会对所有请求进行token验证,无论是访问静态资源还是访问接口。但我明明配置静态资源过滤,可还是会被我的过滤器拦截。
无论如何调换过滤器位置,都无法躲过我的过滤器,所以不能使用这种放行,所以配置
public void configure(WebSecurity web) {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/static/**","/favicon.ico","/error","/index.html");
}
来解决这个问题,这种配置会直接跳过过滤器,不经过过滤器过滤,打断点可以看到
我在请求一进来的
applicationFilterConfig
过滤中, 我们可以看到spring security的过滤器点进去:
配置静态资源不会经过springsecurity的过滤器。
正确配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//自定义用户认证
@Bean
public UserDetailsService userDetailsService(){
return new UserDetailsServiceImpl();
}
//加密算法生成bean
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// 使用自定义登录身份认证组件
JwtAuthenticationProvider jwtAuthenticationProvider = new JwtAuthenticationProvider(userDetailsService());
jwtAuthenticationProvider.setPasswordEncoder(new MyPasswordEncoder());
auth.authenticationProvider(jwtAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/static/**","/favicon.ico","/error","/index.html");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 开启登录认证流程过滤器
http.addFilterBefore(new JwtLoginFilter(authenticationManager()), LogoutFilter.class)
// 访问控制时登录状态检查过滤器
.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), LogoutFilter.class)
//此处需要注意 自定义资源权限认证过滤器需要在异常处理过滤器之后 因为资源权限认证过滤器一般位于登录认证的最后 如果异常过滤器在资源认证过滤器后 将不会生效
.addFilterAfter(getMyFilterSecurityInterceptor(), ExceptionTranslationFilter.class)
.exceptionHandling().accessDeniedHandler(new MyAccessDeineHandler()).authenticationEntryPoint(new MyAuthenticationEntryPoint())
.and()
// 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
.cors().and().csrf().disable()
.headers().frameOptions().disable();
// 退出登录处理器
http.logout().logoutUrl("/loginout").logoutSuccessHandler(new MyLoginOutSuccessHandler());
//禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
public MyFilterSecurityInterceptor getMyFilterSecurityInterceptor() throws Exception {
MyFilterSecurityInterceptor myFilterSecurityInterceptor = new MyFilterSecurityInterceptor();
myFilterSecurityInterceptor.setAuthenticationManager(authenticationManager());
myFilterSecurityInterceptor.setAccessDecisionManager(new MyAccessDecisionManager());
myFilterSecurityInterceptor.setSecurityMetadataSource(new MyInvocationSecurityMetadataSource());
return myFilterSecurityInterceptor;
}
}