千家信息网

SpringBoot Security如何自定义异常处理

发表于:2025-11-16 作者:千家信息网编辑
千家信息网最后更新 2025年11月16日,这篇文章主要为大家展示了"SpringBoot Security如何自定义异常处理",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"SpringBoot Se
千家信息网最后更新 2025年11月16日SpringBoot Security如何自定义异常处理

这篇文章主要为大家展示了"SpringBoot Security如何自定义异常处理",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"SpringBoot Security如何自定义异常处理"这篇文章吧。

    SpringBoot Security自定义异常

    access_denied 方面异常

    原异常

    {    "error": "access_denied",    "error_description": "不允许访问"}

    现异常

    {    "success": false,    "error": "access_denied",    "status": 403,    "message": "不允许访问",    "path": "/user/get1",    "timestamp": 1592378892768}

    实现

    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {    @Override    public void configure(ResourceServerSecurityConfigurer resources) {        // access_denied 方面异常        OAuth3AccessDeniedHandler oAuth3AccessDeniedHandler = new OAuth3AccessDeniedHandler();        oAuth3AccessDeniedHandler.setExceptionTranslator(new CustomWebResponseExceptionTranslator());        resources.accessDeniedHandler(oAuth3AccessDeniedHandler);    }}

    Invalid access token 方面异常

    原异常

    {    "error": "invalid_token",    "error_description": "Invalid access token: 4eb58ecf-e66de-4155-9477-64a1c9805cc8"}

    现异常

    {    "success": false,    "error": "invalid_token",    "status": 401,    "message": "Invalid access token: 8cd45925dbf6-4502-bd13-8101bc6e1d4b",    "path": "/user/get1",    "timestamp": 1592378949452}

    实现

    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {    @Override    public void configure(ResourceServerSecurityConfigurer resources) {         // Invalid access token 方面异常        OAuth3AuthenticationEntryPoint authenticationEntryPoint = new OAuth3AuthenticationEntryPoint();        authenticationEntryPoint.setExceptionTranslator(new CustomWebResponseExceptionTranslator());        resources.authenticationEntryPoint(authenticationEntryPoint);    }}

    Bad credentials 方面异常(登陆出错)

    原异常

    {    "error": "invalid_grant",    "error_description": "用户名或密码错误"}

    现异常

    {    "success": false,    "error": "invalid_grant",    "status": 400,    "message": "用户名或密码错误",    "path": "/oauth/token",    "timestamp": 1592384576019}

    实现

    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {     @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {        endpoints.userDetailsService(detailsService)                .tokenStore(memoryTokenStore())                .exceptionTranslator(new CustomWebResponseExceptionTranslator())                .authenticationManager(authenticationManager)                //接收GET和POST                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);    }}

    其他类

    @Getter@JsonSerialize(using = CustomOauthExceptionSerializer.class)public class CustomOauthException extends OAuth3Exception {    private String oAuth3ErrorCode;    private int httpErrorCode;    public CustomOauthException(String msg, String oAuth3ErrorCode, int httpErrorCode) {        super(msg);        this.oAuth3ErrorCode = oAuth3ErrorCode;        this.httpErrorCode = httpErrorCode;    }}
    public class CustomOauthExceptionSerializer extends StdSerializer {    private static final long serialVersionUID = 2652127645704345563L;    public CustomOauthExceptionSerializer() {        super(CustomOauthException.class);    }    @Override    public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {        gen.writeStartObject();        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();        gen.writeObjectField("success",false);        gen.writeObjectField("error",value.getOAuth3ErrorCode());        gen.writeObjectField("status", value.getHttpErrorCode());        gen.writeObjectField("message", value.getMessage());        gen.writeObjectField("path", request.getServletPath());        gen.writeObjectField("timestamp", (new Date()).getTime());        if (value.getAdditionalInformation()!=null) {            for (Map.Entry entry : value.getAdditionalInformation().entrySet()) {                String key = entry.getKey();                String add = entry.getValue();                gen.writeObjectField(key, add);            }        }        gen.writeEndObject();    }}
    public class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator {    @Override    public ResponseEntity translate(Exception e) throws Exception {        ResponseEntity translate = super.translate(e);        OAuth3Exception body = translate.getBody();        CustomOauthException customOauthException = new CustomOauthException(body.getMessage(),body.getOAuth3ErrorCode(),body.getHttpErrorCode());        ResponseEntity response = new ResponseEntity<>(customOauthException, translate.getHeaders(),                translate.getStatusCode());        return response;    }}

    补充

    {    "error": "invalid_client",    "error_description": "Bad client credentials"}

    如果client_secret错误依然还是报错,如上内容,针对这个异常需要在如下方法中的addTokenEndpointAuthenticationFilter添加过滤器处理

      @Override    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {      oauthServer                // 开启/oauth/token_key验证端口无权限访问                .tokenKeyAccess("permitAll()")                // 开启/oauth/check_token验证端口认证权限访问                .checkTokenAccess("isAuthenticated()")                .addTokenEndpointAuthenticationFilter(null)                .allowFormAuthenticationForClients();    }

    SpringSecurity自定义响应异常信息

    此处的异常信息设置的话,其中还是有坑的,比如你想自定义token过期信息,无效token这些,如果按照SpringSecurity的设置是不会生效的,需要加到资源的配置中。

    如果只是SpringSecurity的话,只需要实现AccessDeniedHandler和AuthenticationEntryPoint这2个接口就可以了。他们都是在ExceptionTranslationFilter中生效的。

    • AuthenticationEntryPoint 用来解决匿名用户访问无权限资源时的异常

    • ruAccessDeineHandler 用来解决认证过的用户访问无权限资源时的异常

    如果你想自定义token过期的话,需要实现AuthenticationEntryPoint这个接口,因为token过期了,访问的话也算是匿名访问。

    但是SpringSecurity的过滤器链中其实是有顺序的,校验token的OAuth3AuthenticationProcessingFilter在它前面,导致一直没有办法生效,所有需要添加到资源的配置上,demo如下:

    /** * @author WGR * @create 2021/8/23 -- 16:52 */@Componentpublic class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {     @Override    public void commence(HttpServletRequest request, HttpServletResponse response,                         AuthenticationException authException) throws ServletException {        Throwable cause = authException.getCause();        try {            if (cause instanceof InvalidTokenException) {                Map map = new HashMap();                map.put("error", "无效token");                map.put("message", authException.getMessage());                map.put("path", request.getServletPath());                map.put("timestamp", String.valueOf(new Date().getTime()));                response.setContentType("application/json");                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);                try {                    ObjectMapper mapper = new ObjectMapper();                    mapper.writeValue(response.getOutputStream(), map);                } catch (Exception e) {                    throw new ServletException();                }            }        } catch (Exception e) {            e.printStackTrace();        }    }}

    则可以生效,返回信息具体如下:

    如果想设置没有权限的自定义异常信息的话:

    /** * @author WGR * @create 2021/8/23 -- 17:09 */@Componentpublic class SimpleAccessDeniedHandler implements AccessDeniedHandler {    @Override    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {        Map map = new HashMap();        map.put("message", "无权操作");        map.put("path", request.getServletPath());        map.put("timestamp", String.valueOf(new Date().getTime()));        response.setContentType("application/json");        response.setStatus(HttpServletResponse.SC_FORBIDDEN);        try {            ObjectMapper mapper = new ObjectMapper();            mapper.writeValue(response.getOutputStream(), map);        } catch (Exception e) {            throw new ServletException();        }    }}

    把它设置到springsecurity中,添加进去就可以了,如果不是想要捕获token过期的话,就直接添加进去也可以

    以上是"SpringBoot Security如何自定义异常处理"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

    信息 方面 权限 处理 内容 用户 资源 篇文章 错误 密码 接口 用户名 端口 过滤器 还是 学习 帮助 认证 配置 验证 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 服务器要来到的歌 世界网络安全资讯网站 腾讯中国互联网科技 浩顺考勤机如何导入数据库 服务器安全黑白名单 从国家安全角度解读网络安全法 web服务器模式 网络安全法处罚 医院 长沙互联网络科技有限公司 客户服务器风格的体系结构 软件开发的过程及优缺点 保靖公安局网络安全 陵水市网络安全检查 怕一个数据库丢失数据怎么办 湖北云三软件开发有限公司 数据库复制翻译 阿里云代购服务器安全吗 公司网络安全不到位怎么处罚 深圳字节跳动软件开发组地址 网络安全与信息国家战略 杭州erp软件开发公司哪个好 中国科技与互联网发展前景 浩顺考勤机如何导入数据库 警务室网络安全宣传周简报 高碑店网络安全宣传 jsp数据库图片引入路径 国内外数据库技术发展现状 宁波舜宇车载光学技术软件开发 保证网络安全应做到哪些 sql语句修改数据库属性值
    0