Spring Security 实战干货:自定义异常处理

转自:https://www.cnblogs.com/felordcn/p/12142514.html

文章目录

  • 1. 前言
  • 2. Spring Security 中的异常
    • 2.1 AuthenticationException
    • 2.2 AccessDeniedException
  • 3. Http 状态对认证授权的规定
    • 3.1 401 未授权状态
    • 3.2 403 被拒绝状态
  • 4. Spring Security 中的异常处理
    • 4.1 实现 AuthenticationEntryPoint
    • 4.2 实现 AccessDeniedHandler
    • 4.3 个人实践建议
    • 4.4 配置
  • 5. 总结

1. 前言

最近实在比较忙,很难抽出时间来继续更 Spring Security 实战干货系列。今天正好项目中 Spring Security 需要对认证授权异常的处理,就分享出来吧 。

2. Spring Security 中的异常

Spring Security 中的异常主要分为两大类:一类是认证异常,另一类是授权相关的异常。

2.1 AuthenticationException

AuthenticationException 是在用户认证的时候出现错误时抛出的异常。主要的子类如图:

根据该图的信息,系统用户不存在,被锁定,凭证失效,密码错误等认证过程中出现的异常都由 AuthenticationException 处理。

2.2 AccessDeniedException

AccessDeniedException 主要是在用户在访问受保护资源时被拒绝而抛出的异常。同 AuthenticationException 一样它也提供了一些具体的子类。如下图:

AccessDeniedException 的子类比较少,主要是 CSRF 相关的异常和授权服务异常。

3. Http 状态对认证授权的规定

Http 协议对认证授权的响应结果也有规定。

3.1 401 未授权状态

HTTP 401 错误 - 未授权(Unauthorized) 一般来说该错误消息表明您首先需要登录(输入有效的用户名和密码)。 如果你刚刚输入这些信息,立刻就看到一个 401 错误,就意味着,无论出于何种原因您的用户名和密码其中之一或两者都无效(输入有误,用户名暂时停用,账户被锁定,凭证失效等) 。总之就是认证失败了。其实正好对应我们上面的 AuthenticationException 。

3.2 403 被拒绝状态

HTTP 403 错误 - 被禁止(Forbidden) 出现该错误表明您在访问受限资源时没有得到许可。服务器理解了本次请求但是拒绝执行该任务,该请求不该重发给服务器。并且服务器想让客户端知道为什么没有权限访问特定的资源,服务器应该在返回的信息中描述拒绝的理由。一般实践中我们会比较模糊的表明原因。 该错误对应了我们上面的 AccessDeniedException 。

4. Spring Security 中的异常处理

我们在 Spring Security 实战干货系列文章中的 自定义配置类入口 WebSecurityConfigurerAdapter 一文中提到 HttpSecurity 提供的 exceptionHandling() 方法用来提供异常处理。该方法构造出 ExceptionHandlingConfigurer 异常处理配置类。该配置类提供了两个实用接口:

  • AuthenticationEntryPoint 该类用来统一处理 AuthenticationException 异常
  • AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常

我们只要实现并配置这两个异常处理类即可实现对 Spring Security 认证授权相关的异常进行统一的自定义处理。

4.1 实现 AuthenticationEntryPoint

以 json 信息响应。

 import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.http.MediaType;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;/*** @author dax* @since 2019/11/6 22:11*/public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {//todo your businessHashMap<String, String> map = new HashMap<>(2);map.put("uri", request.getRequestURI());map.put("msg", "认证失败");response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setCharacterEncoding("utf-8");response.setContentType(MediaType.APPLICATION_JSON_VALUE);ObjectMapper objectMapper = new ObjectMapper();String resBody = objectMapper.writeValueAsString(map);PrintWriter printWriter = response.getWriter();printWriter.print(resBody);printWriter.flush();printWriter.close();}}

4.2 实现 AccessDeniedHandler

同样以 json 信息响应。

 import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.http.MediaType;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;/*** @author dax* @since 2019/11/6 22:19*/public class SimpleAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {//todo your businessHashMap<String, String> map = new HashMap<>(2);map.put("uri", request.getRequestURI());map.put("msg", "认证失败");response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.setCharacterEncoding("utf-8");response.setContentType(MediaType.APPLICATION_JSON_VALUE);ObjectMapper objectMapper = new ObjectMapper();String resBody = objectMapper.writeValueAsString(map);PrintWriter printWriter = response.getWriter();printWriter.print(resBody);printWriter.flush();printWriter.close();}}

4.3 个人实践建议

其实我个人建议 Http 状态码 都返回 200 而将 401 状态在 元信息 Map 中返回。因为异常状态码在浏览器端会以 error 显示。我们只要能捕捉到 401 和 403 就能认定是认证问题还是授权问题。

4.4 配置

实现了上述两个接口后,我们只需要在 WebSecurityConfigurerAdapter 的 configure(HttpSecurity http) 方法中配置即可。相关的配置片段如下:

 http.exceptionHandling().accessDeniedHandler(new SimpleAccessDeniedHandler()).authenticationEntryPoint(new SimpleAuthenticationEntryPoint())

5. 总结

今天我们对 Spring Security 中的异常处理进行了讲解。分别实现了自定义的认证异常处理和自定义的授权异常处理。相关的 DEMO 可关注微信公众号: Felordcn 回复 ss07 获取。

关注公众号:Felordcn获取更多资讯

Spring Security 实战干货:自定义异常处理相关推荐

  1. Spring Security 实战:自定义异常处理

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 最近实在比较忙,很难抽出时间来继续更  [S ...

  2. Spring Security 实战干货: RBAC权限控制概念的理解

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 码农小胖哥 来源 | 公众号「码农小胖哥」 1 ...

  3. Spring Security 实战干货:实现自定义退出登录

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 上一篇对 Spring Security 所 ...

  4. Spring Security 实战干货:玩转自定义登录

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 前面的关于 Spring Security  ...

  5. Spring Security 实战干货:OAuth2登录获取Token的核心逻辑

    作者 | 码农小胖哥 来源 | https://mp.weixin.qq.com/s/zdTBdSVunqwVGx-spHjLjw 1. 前言 在上一篇Spring Security 实战干货:OAu ...

  6. Spring Security 实战干货:客户端OAuth2授权请求的入口在哪里

    1. 前言 在Spring Security 实战干货:OAuth2 第三方授权初体验一文中我先对 OAuth2.0 涉及的一些常用概念进行介绍,然后直接通过一个 DEMO 来让大家切身感受了 OAu ...

  7. Spring Security 实战干货:OAuth2授权回调的核心认证流程

    1. 前言 我们在上一篇 Spring Security 实战干货:OAuth2 授权回调的处理机制 对 OAuth2 服务端调用客户端回调的流程进行了图解, 今天我们来深入了解 OAuth2 在回调 ...

  8. Spring Security 实战干货:自定义配置类入口 WebSecurityConfigurerAdapter

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 今天我们要进一步的的学习如何自定义配置 Sp ...

  9. Spring Security 实战干货:从零手写一个验证码登录

    1. 前言 前面关于Spring Security胖哥又写了两篇文章,分别图文并茂地介绍了UsernamePasswordAuthenticationFilter和 AuthenticationMan ...

最新文章

  1. 代码注释规范-google版本
  2. DQN 笔记 State-action Value Function(Q-function)
  3. html5/css3响应式页面开发总结
  4. 如何通过 Impex 在 SAP Commerce Cloud 创建一个新的 Component
  5. 直播预告 - 微软MVP为你揭秘Visual Studio 2019新特性
  6. 3.1HTML5样式的使用
  7. c语言手写指针和乘号,C-学会使用指针(示例代码)
  8. wps office oa控件 痕迹_WPS加载项案例应用回顾
  9. mkdir: 无法创建目录“/home/lj/.tldr“: 文件已存在
  10. 苹果电池健康几天掉1点
  11. 设置网页只允许在手机微信浏览器打开
  12. 6阶群的非平凡子群_当|G|=8时,群lt;G,*gt;只能有?阶非平凡子群,不能有?阶子群,平凡子群为?...
  13. Mathworks MATLAB for Mac (强大的商业数学软件) v9.11
  14. 跨行业数据挖掘标准流程
  15. XAMPP下载、安装步骤以及安装后遇到的各种问题的解决
  16. 华为,一口气签约3所大学!
  17. HBase+Spark技术双周刊第一期
  18. 使用致远OA系统,打开Excel类型文件,提示office编辑程序未安装
  19. 如何理解IGBT的热阻和热阻抗?
  20. php代码如何在dw输入,Dreamweaver CC

热门文章

  1. Spring cloud 微服务docker容器化最佳实践
  2. 2022-2028年中国智慧物流行业深度调研及投资前景预测报告(全卷)
  3. Docker学习(六)-----Docker数据卷
  4. LeetCode19. Remove Nth Node From End of List 删除链表中的倒数第n个位置的元素
  5. SpringCloud Alibaba微服务实战(四) - Nacos Config 配置中心
  6. java 16进制与图片互转
  7. 合肥工业大学—SQL Server数据库实验五:创建和删除索引
  8. 华为八爪鱼自动驾驶云
  9. MLIR中间表示和编译器框架
  10. GPU上的基本线性代数