Spring Cloud 集成 Spring Security和Oauth2.0实现认证授权(三)认证中心异常处理

426 阅读1分钟

自定义异常处理返回结果

Spring Security Oauth2通过WebResponseExceptionTranslator来处理用户认证时出现的异常,而在认证之前对客户端进行认证时和Spring Security认证流程没有太大差异。 自定义GlobalOauth2ExceptionHandler实现WebResponseExceptionTranslator,重写返回参数。

@Component
public class GlobalOauth2ExceptionHandler implements WebResponseExceptionTranslator<OAuth2Exception> {


    private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

    @Override
    public ResponseEntity<OAuth2Exception> translate(Exception e) {

        // Try to extract a SpringSecurityException from the stacktrace
        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
        Exception ase;
        // 通过逐级判断异常类型进行相应的处理,和原生的DefaultWebResponseExceptionTranslator实现并无太大差异

        ase = (UnsupportedGrantTypeException) throwableAnalyzer.getFirstThrowableOfType(UnsupportedGrantTypeException.class, causeChain);

        if (ase != null) {
            return handleOAuth2Exception(new ServerOauth2Exception("不支持的授权类型!!!", e));
        }

        ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
                causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new ServerOauth2Exception(e.getMessage(), e));
        }

        ase = (AccessDeniedException) throwableAnalyzer
                .getFirstThrowableOfType(AccessDeniedException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new ServerOauth2Exception(ase.getMessage(), ase));
        }

        ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(
                HttpRequestMethodNotSupportedException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new ServerOauth2Exception(ase.getMessage(), ase));
        }

        ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(
                OAuth2Exception.class, causeChain);

        if (ase != null) {
            return handleOAuth2Exception((OAuth2Exception) ase);
        }

        return handleOAuth2Exception(new ServerOauth2Exception("服务器内部错误!!!", e));

    }

    private ResponseEntity<OAuth2Exception> handleOAuth2Exception(OAuth2Exception e) {

        int status = e.getHttpErrorCode();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
            headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
        }

        return new ResponseEntity<>(e, headers,
                HttpStatus.OK);
    }
}

自定义异常类继承Oauth2Exception

通过自定义的异常类继承Oauth2Exception,只保留我们需要展示的信息,摒弃了Oauth2Exception原来展示的异常信息

@JsonSerialize(using = ServerOauth2ExceptionSerializer.class)
public class ServerOauth2Exception extends OAuth2Exception {

    public ServerOauth2Exception(String msg) {
        super(msg);
    }

    public ServerOauth2Exception(String msg, Throwable t) {
        super(msg, t);
    }
}

认证失败和授权失败处理器

@Component
public class GlobalAccessDeniedHandler implements AccessDeniedHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalAccessDeniedHandler.class);

    // 自定义授权失败异常处理器
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        logger.error(accessDeniedException.getMessage());
        R<Object> result = R.fail(HttpCodeStatus.FORBIDDEN, "授权失败,您暂时无法访问服务!!!");
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream out = response.getOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        out.write(objectMapper.writeValueAsBytes(result));
        out.flush();
        out.close();
    }
}
@Component
public class GlobalAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private Logger logger = LoggerFactory.getLogger(GlobalAuthenticationEntryPoint.class);

    // 自定义认证返回实体
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        logger.error(authException.getMessage());
        R<Object> result = R.fail(HttpCodeStatus.UNAUTHORIZED, "认证失败,请检查账号密码!!!");
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream out = response.getOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        out.write(objectMapper.writeValueAsBytes(result));
        out.flush();
        out.close();
    }
}