Sping Security (五):其余知识点

119 阅读2分钟

前面篇幅已经将spring Security的认证、授权流程、跨域问题讲得差不多了。这一篇主要补充一下剩余的一些知识点,主要包括CSRF、认证失败、授权失败处理器相关知识点。

说明: 本系列的文章使用的是 springBoot 2.7.11 (springboot 2x 最后一个稳定版本),对应的 Spring Security 是 5.7.8

CSRF

简单说就是为了安全起见,浏览器和服务端每次通讯时,服务端会随机给浏览器发一个随机token值,放到请求头/响应头里 csrf_token = xxxx,然后每次都进行验证。

image.png

具体详见 CSRF攻击与防御

实质上这个csrf_token 跟我们使用的token鉴权方案是非常像的。也就是使用token鉴权天然解决了CSRF问题,因此不再需要Spring Security再来做这个检查了。
而且前后端分离项目,前端每次请求都是无状态的,本身也是没用csrf_token 这个请求头的,因此需要主动关闭。

@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
    //使用由httpSecurityConfiguration 装配的 HttpSecurity 则会紧密的保持原有的过滤器
    http.csrf().disable()//前后端分离项目要关闭 csrf
    ...
}

认证失败处理器

  • 自定义 AuthenticationEntryPoint
/**
 * 认证失败出现的异常处理
 * @author 
 * @date 2023/6/7 21:59
 **/
@Component
public class AuthenticationEntryImpl implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {
        Result result = Result.error("用户认证失败请查询登录");
        WebUtils.renderString(response, JSON.toJSONString(result));
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
    }

}
  • 添加 Security Config

@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;


// 配置异常处理器
http.exceptionHandling()
        .authenticationEntryPoint(authenticationEntryPoint)

授权失败处理器

  • 自定义AccessDeniedHandler

    @Component
    public class AccessDeniedHandlerImpl implements AccessDeniedHandler {

        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
            Result result = Result.error("您无权访问该接口");
            WebUtils.renderString(response, JSON.toJSONString(result));
            response.setStatus(HttpStatus.FORBIDDEN.value());
        }

    }
  • 添加 Security Config
@Autowired
private AccessDeniedHandler accessDeniedHandler;


// 配置异常处理器
http.exceptionHandling()
    .accessDeniedHandler(accessDeniedHandler)

可能按照上面流程配置了认证失败、授权失败的处理器,但是没有执行到处理器中,这时候要看下是不是开启了全局异常捕获,需要手动抛出这2个异常。

/**
 * 全局异常处理
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

   ...

    /**
     * 排除掉security 2个异常
     * @param e
     */
    @ExceptionHandler(AuthenticationException.class)
    public void AuthenticationExceptionResolve(AuthenticationException e) {

        throw e;
    }


    @ExceptionHandler(AccessDeniedException.class)
    public void AccessDeniedExceptionResolve(AccessDeniedException  e) {

        throw e;
    }

}