06.授权服务器自定义返回数据

Spring Security是自带一套异常处理系统的,自定义返回数据有两种方式:

方式一(较麻烦不推荐):

  1. 自定义异常,继承OAuth2Exception
@JsonSerialize(using = ExtendOAuth2ExceptionSerializer.class)
public class ExtendOAuth2Exception extends OAuth2Exception {




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

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

}

public class GrantTypeException extends ExtendOAuth2Exception{

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

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

    @Override
    public String getOAuth2ErrorCode() {
        return "grant_type_unsupported---不支持当前授权类型!!!";
    }

    @Override
    public int getHttpErrorCode() {
        return 400;
    }

}
  1. 在校验的代码处(Granter或Provider处,一般是在Provider处做校验)抛出异常
@Data
@Component("SmsCodeAuthenticationProvider")
public class SmsCodeAuthenticationProvider  implements AuthenticationProvider {
    @Resource(name = "MobileUserDetailsService")
    private MobileUserDetailsService userDetailsService;

    @Autowired
    private CheckCodeClient checkCodeClient;

    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();




    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
        String mobile = (String) authenticationToken.getPrincipal();
        String code = (String) authenticationToken.getCredentials();
        UserDetails userDetails =userDetailsService.loadUserByMobile(mobile);
        if (null==userDetails){
            throw new InvalidInformationException("该电话号码为注册",null);
        }
        Boolean b = checkCodeClient.verifySmsCheckCode(mobile, code);
        // 验证码比对
        if (!b) {
            throw new InvalidInformationException("验证码错误",null);
        }

        SmsCodeAuthenticationToken result = new SmsCodeAuthenticationToken(userDetails,userDetails.getPassword(),userDetails.getAuthorities());
        result.setDetails(authentication.getDetails());
        return result;
    }



    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }


}
  1. 编写translator,重写translate方法,在translate方法中可以对自定义的异常进行处理
@Slf4j
public class OAuthServerWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
    private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

    @Override
    public ResponseEntity translate(Exception e) throws Exception {

        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
        Exception ase = null;// 异常栈获取 OAuth2Exception 异常

        //自定义认证方式异常
        ase=(UnsupportedGrantTypeException) throwableAnalyzer
                .getFirstThrowableOfType(UnsupportedGrantTypeException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new GrantTypeException(e.getMessage(), e));
        }

        //自定义未认证异常
        ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class,
                causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase));
        }

        //自定义方法不允许访问异常
        ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer
                .getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new MethodNotAllowedException(ase.getMessage(), ase));
        }

        //自定义认证失败异常
        ase = (InvalidInformationException) throwableAnalyzer
                .getFirstThrowableOfType(InvalidInformationException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new InvalidInformationException(ase.getMessage(), ase));
        }


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

        //自定义其他异常
        ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);

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


        // 不包含上述异常则服务器内部错误
        return handleOAuth2Exception(new ServerErrorException(HttpStatus.OK.getReasonPhrase(), 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()));
//        }
//        log.error("内部产生异常", e);
//
//        return new ResponseEntity<>(e, headers,
//                HttpStatus.valueOf(status));
//    }

    private ResponseEntity<HttpResponseEntity> handleOAuth2Exception(OAuth2Exception e) {


        log.error("内部产生异常", 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()));
        }

        HttpResponseEntity responseEntity=new HttpResponseEntity();

        if(e instanceof InvalidInformationException){
            responseEntity.setCode(Code.LOGIN_ERR);
            responseEntity.setMessage(e.getMessage());
        }else {
            responseEntity.setCode(Code.PROJECT_BUSINESS_ERROR);
            responseEntity.setMessage(e.getMessage());
        }

        return new ResponseEntity<>(responseEntity, headers,
                HttpStatus.valueOf(status));
    }

}

  1. 使用该translator
    @Override // 令牌端点的安全约束配置
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenServices(tokenService())//令牌管理服务
                .authenticationManager(authenticationManager)//认证管理器
                .allowedTokenEndpointRequestMethods(HttpMethod.POST)
                .accessTokenConverter(accessTokenConverter)
                .tokenStore(tokenStore)
                .setClientDetailsService(clientDetails());//客户端信息服务
        //获取原有默认的授权者(那四种模式)
        ArrayList<TokenGranter> tokenGranters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
        //添加扩展的验证码模式授权者
        tokenGranters.add(new CaptchaTokenGranter(endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager,checkCodeClient));
        //添加扩展的邮箱密码模式授权者
        tokenGranters.add(new EmailPwdGranter(authenticationManager,endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        //添加扩展的短信验证码模式授权者
        tokenGranters.add(new SmsCodeTokenGranter(endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager));
        //添加自定义的用户名密码模式授权者
        tokenGranters.add(new MyUsernamePasswordGranter(authenticationManager,endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        CompositeTokenGranter compositeTokenGranter=new CompositeTokenGranter(tokenGranters);



               endpoints.tokenGranter(compositeTokenGranter);        //配置授权者
        
        endpoints.exceptionTranslator(new OAuthServerWebResponseExceptionTranslator());//配置异常转换器

    }

方式二(推荐):

绕过Spring Security的异常处理机制,自己处理:

  1. 定义controller
@RestController
@RequestMapping("/oauth")
public class AuthController {

    @Autowired
    private TokenEndpoint tokenEndpoint;

    /**
     * Oauth2登录认证
     */
    @RequestMapping(value = "/token", method = RequestMethod.POST)
    public HttpResponseEntity postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {

        OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
        Oauth2TokenDto oauth2TokenDto = Oauth2TokenDto.builder()
                .token(oAuth2AccessToken.getValue())
                .refreshToken(oAuth2AccessToken.getRefreshToken().getValue())
                .expiresIn(oAuth2AccessToken.getExpiresIn())
                .tokenHead("Bearer ").build();

        return new HttpResponseEntity(Code.LOGIN_OK,oauth2TokenDto,"登录成功!!!");
    }
}
  1. 定义异常处理器
@ControllerAdvice
public class Oauth2ExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = OAuth2Exception.class)
    public HttpResponseEntity handleOauth2(OAuth2Exception e) {
        e.printStackTrace();
        return new HttpResponseEntity(Code.LOGIN_ERR, e,e.getMessage());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值