- security最初的配置
- 初步改进后的配置
- 排查真实原因
- 更加合理的配置
之前写了篇关于security认证的文章 感觉对security了解多了一点,直到遇到过滤器层面的问题,才明白security终究还是那个复杂的security。 security最初的配置
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 登录成功处理类
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
http.authorizeRequests()
//静态文件允许访问
.antMatchers().permitAll()
// 放行
.antMatchers( "/assets
@Override
public void configure(WebSecurity web) throws Exception {
// 直接放行了 如果是login接口 必须通过HttpSecurity 走过滤链 因为登录涉及 SecurityContextHolder
web.ignoring().antMatchers("/test)就是说我们没有传httpMethod
// httpMethod 为null 不走该判断
if (this.httpMethod != null && StringUtils.hasText(request.getMethod()) && this.httpMethod != valueOf(request.getMethod())) {
if (logger.isDebugEnabled()) {
logger.debug("Request '" + request.getMethod() + " " + this.getRequestPath(request) + "' doesn't match '" + this.httpMethod + " " + this.pattern + "'");
}
return false;
// 如果antMatchers(
// 可以看到除了 "GET", "HEAD", "TRACE", "OPTIONS" 四种方式 其它请求都会被拦截
if (!this.requireCsrfProtectionMatcher.matches(request)) {
filterChain.doFilter(request, response);
} else {
// 其它请求 没有token会被拦截
String actualToken = request.getHeader(csrfToken.getHeaderName());
if (actualToken == null) {
actualToken = request.getParameter(csrfToken.getParameterName());
}
if (!csrfToken.getToken().equals(actualToken)) {
if (this.logger.isDebugEnabled()) {
// 我们在控制台看到的输出
this.logger.debug("Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request));
}
if (missingToken) {
this.accessDeniedHandler.handle(request, response, new MissingCsrfTokenException(actualToken));
} else {
this.accessDeniedHandler.handle(request, response, new InvalidCsrfTokenException(csrfToken, actualToken));
}
} else {
filterChain.doFilter(request, response);
}
}
}
这就是为什么我们get请求可以访问 而put,delete等请求失败的原因。
更加合理的配置
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 登录成功处理类
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
http.authorizeRequests()
//静态文件允许访问
.antMatchers().permitAll()
// 放行
.antMatchers( "/assets/**","/login","/test/**","/testfather/**","/testes/**","/advice/**","css/**","/js/**","/image/*").permitAll()
//其他所有请求需要登录, anyRequest 不能配置在 antMatchers 前面
.anyRequest().authenticated()
.and()
//登录页面配置,用于替换security默认页面
.formLogin().loginPage( "/login").successHandler(successHandler).and()
//登出页面配置,用于替换security默认页面
.logout().logoutUrl( "/logout").and()
.httpBasic().and()
// 开启了csrf防御 如果要放行/test/** 还需要在下面ignoringAntMatchers进行配置
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// 这里还需要放行 当然如果是 .csrf().disable()就不会有这个问题了
.ignoringAntMatchers(
"/instances",
"/actuator/**",
"/test/**",
"/advice/**",
"/testes/**"
);
}
}
为什么有的项目没有ignoringAntMatchers配置也放行成功了呢? 因为那些项目 很可能直接.csrf().disable() 所以不会出现该问题
题外话: 想必可能有同学听过 controller层接口必须捕获异常 ,如果不捕获 其中坑点之一就和这个security框架的.csrf()有关:
* 异常没有捕获 ==》 * 如果当开启了 csrf 且又没有放行时 (在 WebSecurity 放行了 否则进不来接口) 异常会抛到 security 导致security报错(同样需要debug级别日志查看 error看不到) 且返回401 * 换句话说:WebSecurity放行的方式 还需配合接口的try catch 否则接口报错了 也会返回401 * 当然 其它情况可能也会因为异常没捕获 而造成未知结果 * 所以我们还是应该遵循规范:接口必须异常捕获



