Spring Security(八) —— 异常处理

本文介绍了SpringSecurity框架中的异常体系,包括AuthenticationException和AccessDeniedException,并详细阐述了如何自定义认证和授权异常处理,通过创建CustomAuthenticationEntryPoint和CustomAccessDeniedHandler实现异常信息的返回。最后展示了在configure方法中配置自定义异常处理的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:异常体系

Spring Security中异常主要分为两大类:

  • AuthenticationException:认证异常
  • AccessDeniedException:授权异常

其中认证所涉及的异常类型比较多,默认有18种,如下:
在这里插入图片描述
相比于认证异常,权限异常类就要少了很多,默认提供的权限异常如下:
在这里插入图片描述

二:自定义异常配置

在实际开发中,默认异常是无法满足需求的,需要大量的自定义异常类,Spring Security提供了两个方法来配置:

  • authenticationEntryPoint():认证自定义异常
  • accessDeniedHandler():授权自定义异常

至于这两个方法怎么使用,我们可以进入源码看看

首先是authenticationEntryPoint(),可以看到,该方法要求我们传入AuthenticationEntryPoint的对象

	public ExceptionHandlingConfigurer<H> authenticationEntryPoint(
			AuthenticationEntryPoint authenticationEntryPoint) {
		this.authenticationEntryPoint = authenticationEntryPoint;
		return this;
	}

进入AuthenticationEntryPoint接口,可以看到只有一个方法,因此在authenticationEntryPoint方法中可以直接传入Lambda表达式,但那样写不美观,配置与实现应该分离,因此我们可以新建一个类去实现这个接口

public interface AuthenticationEntryPoint {
	/**
	 * 处理认证访问相关异常
	 * @param request 导致AuthenticationException的请求
	 * @param response 响应
	 * @param authException 异常信息
	 */
	void commence(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException authException) throws IOException, ServletException;
}
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 400);
        result.put("msg", authException.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

accessDeniedHandler()方法同理,其源码如下:

	public ExceptionHandlingConfigurer<H> accessDeniedHandler(
			AccessDeniedHandler accessDeniedHandler) {
		this.accessDeniedHandler = accessDeniedHandler;
		return this;
	}

进入AccessDeniedHandler接口:

public interface AccessDeniedHandler {
	/**
	 * 处理权限访问相关异常
	 * @param request 导致AccessDeniedException的请求
	 * @param response 响应
	 * @param accessDeniedException 异常信息
	 */
	void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException,
			ServletException;
}

因此我们可以这样实现:

public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 400);
        result.put("msg", accessDeniedException.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
    }
}

最后再在configure中将自定义处理配置进去:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/hello1").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .successHandler(new CustomAuthenticationSuccessHandler())
                .failureHandler(new CustomAuthenticationFailureHandler())
                .and()
                .logout()
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                // 异常处理
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())  // 认证异常
                .accessDeniedHandler(new CustomAccessDeniedHandler())  // 授权异常;
    }

如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:瞳孔的个人网站

### 自定义 Spring Security 异常处理机制 为了实现更灵活的错误响应,在 Spring Security 中可以自定义异常处理逻辑。这不仅有助于提高用户体验,还能增强系统的健壮性和可维护性。 #### 创建全局异常处理器 通过创建一个实现了 `HandlerExceptionResolver` 接口或标注有 `@ControllerAdvice` 注解的类来捕获并处理未被控制器层捕捉到的安全相关异常[^1]: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<String> handleAccessDeniedException() { return new ResponseEntity<>("You do not have permission to access this resource.", HttpStatus.FORBIDDEN); } @ExceptionHandler(AuthenticationException.class) public ResponseEntity<String> handleAuthenticationException() { return new ResponseEntity<>("Invalid credentials provided.", HttpStatus.UNAUTHORIZED); } } ``` 上述代码片段展示了两个常见的安全异常——访问拒绝 (`AccessDeniedException`) 和认证失败 (`AuthenticationException`) 的处理方式。每当这些特定类型的异常抛出时,就会触发相应的方法执行,并返回带有适当 HTTP 状态码的消息给客户端。 #### 配置自定义的身份验证入口点 对于想要改变默认行为的情况,比如当用户尝试登录但未能成功时所看到的信息页面或者重定向路径,则可以通过设置自定义的身份验证入口来进行调整: ```java @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling() .authenticationEntryPoint(new CustomAuthenticationEntryPoint()); } // 定义自己的 AuthenticationEntryPoint 实现 public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { // 设置响应头和状态码等操作... response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); } } ``` 这里展示了一个简单的例子,其中 `CustomAuthenticationEntryPoint` 类负责在发生未经授权请求的情况下向客户端发送 401 错误以及一条消息说明原因。 #### 使用过滤器链中的异常转换器 有时可能希望将某些内部发生的低级异常映射成更高层次的应用程序级别的异常以便更好地控制其传播范围。这时可以在配置文件里指定一个 `ExceptionTranslationFilter` 来完成这项工作: ```java @Bean public ExceptionTranslationFilter exceptionTranslationFilter() { ExceptionTranslationFilter filter = new ExceptionTranslationFilter(); // 可以为不同的原始异常类型分配对应的高级别异常对象 Map<Class<? extends Throwable>, AccessDeniedException> mapping = Collections.singletonMap( SomeInternalException.class, (AccessDeniedException)new AccessDeniedException("Mapped from internal error.") ); filter.setExceptionMapping(mapping); return filter; } ``` 这段代码允许开发者根据实际需求定义从一种异常到另一种之间的映射关系,从而简化了跨组件间的异常管理流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值