溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot?Security如何自定義異常處理

發(fā)布時(shí)間:2021-12-20 10:27:19 來源:億速云 閱讀:205 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“SpringBoot Security如何自定義異常處理”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“SpringBoot Security如何自定義異常處理”這篇文章吧。

    SpringBoot Security自定義異常

    access_denied 方面異常

    原異常

    {
        "error": "access_denied",
        "error_description": "不允許訪問"
    }

    現(xiàn)異常

    {
        "success": false,
        "error": "access_denied",
        "status": 403,
        "message": "不允許訪問",
        "path": "/user/get1",
        "timestamp": 1592378892768
    }

    實(shí)現(xiàn)

    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"
    }

    現(xiàn)異常

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

    實(shí)現(xiàn)

    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 方面異常(登陸出錯(cuò))

    原異常

    {
        "error": "invalid_grant",
        "error_description": "用戶名或密碼錯(cuò)誤"
    }

    現(xiàn)異常

    {
        "success": false,
        "error": "invalid_grant",
        "status": 400,
        "message": "用戶名或密碼錯(cuò)誤",
        "path": "/oauth/token",
        "timestamp": 1592384576019
    }

    實(shí)現(xiàn)

    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<CustomOauthException> {
        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<String, String> 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<OAuth3Exception> translate(Exception e) throws Exception {
            ResponseEntity<OAuth3Exception> translate = super.translate(e);
            OAuth3Exception body = translate.getBody();
            CustomOauthException customOauthException = new CustomOauthException(body.getMessage(),body.getOAuth3ErrorCode(),body.getHttpErrorCode());
            ResponseEntity<OAuth3Exception> response = new ResponseEntity<>(customOauthException, translate.getHeaders(),
                    translate.getStatusCode());
            return response;
        }
    }

    補(bǔ)充

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

    如果client_secret錯(cuò)誤依然還是報(bào)錯(cuò),如上內(nèi)容,針對(duì)這個(gè)異常需要在如下方法中的addTokenEndpointAuthenticationFilter添加過濾器處理

      @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
          oauthServer
                    // 開啟/oauth/token_key驗(yàn)證端口無權(quán)限訪問
                    .tokenKeyAccess("permitAll()")
                    // 開啟/oauth/check_token驗(yàn)證端口認(rèn)證權(quán)限訪問
                    .checkTokenAccess("isAuthenticated()")
                    .addTokenEndpointAuthenticationFilter(null)
                    .allowFormAuthenticationForClients();
        }

    SpringSecurity自定義響應(yīng)異常信息

    此處的異常信息設(shè)置的話,其中還是有坑的,比如你想自定義token過期信息,無效token這些,如果按照SpringSecurity的設(shè)置是不會(huì)生效的,需要加到資源的配置中。

    如果只是SpringSecurity的話,只需要實(shí)現(xiàn)AccessDeniedHandler和AuthenticationEntryPoint這2個(gè)接口就可以了。他們都是在ExceptionTranslationFilter中生效的。

    • AuthenticationEntryPoint 用來解決匿名用戶訪問無權(quán)限資源時(shí)的異常

    • ruAccessDeineHandler 用來解決認(rèn)證過的用戶訪問無權(quán)限資源時(shí)的異常

    SpringBoot?Security如何自定義異常處理

    如果你想自定義token過期的話,需要實(shí)現(xiàn)AuthenticationEntryPoint這個(gè)接口,因?yàn)閠oken過期了,訪問的話也算是匿名訪問。

    但是SpringSecurity的過濾器鏈中其實(shí)是有順序的,校驗(yàn)token的OAuth3AuthenticationProcessingFilter在它前面,導(dǎo)致一直沒有辦法生效,所有需要添加到資源的配置上,demo如下:

    /**
     * @author WGR
     * @create 2021/8/23 -- 16:52
     */
    @Component
    public 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();
            }
        }
    }

    SpringBoot?Security如何自定義異常處理

    則可以生效,返回信息具體如下:

    SpringBoot?Security如何自定義異常處理

    如果想設(shè)置沒有權(quán)限的自定義異常信息的話:

    /**
     * @author WGR
     * @create 2021/8/23 -- 17:09
     */
    @Component
    public class SimpleAccessDeniedHandler implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
            Map map = new HashMap();
            map.put("message", "無權(quán)操作");
            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();
            }
        }
    }

    把它設(shè)置到springsecurity中,添加進(jìn)去就可以了,如果不是想要捕獲token過期的話,就直接添加進(jìn)去也可以

    SpringBoot?Security如何自定義異常處理

    SpringBoot?Security如何自定義異常處理

    以上是“SpringBoot Security如何自定義異常處理”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI