各位老铁们,大家好,今天由我来为大家分享Spring Cloud Alibaba 实战之 OAuth2 认证服务器自定义异常,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
[[380491]]
前言今天的内容主要是解决一个粉丝提出的问题:如何自定义认证服务器在使用Spring Security OAuth2时返回异常。
那么首先我们以Password模式为例,看看认证过程中可能会出现哪些异常情况。
授权模式错误这里我们特意将授权模式密码改为password1,认证服务器返回异常如下图
{'error':'unsupported_grant_type','error_description':'Unsupportedgranttype:password1'}密码错误如果您在认证时故意输入错误的用户名或密码,将会出现以下异常错误:
{'error':'invalid_grant','error_description':'Badcredentials'}客户端错误身份验证时故意输入错误的client_id 或client
{'error':'invalid_client','error_description':'Badclientcredentials'} 上面的返回结果非常不友好,前端代码很难判断到底是什么错误,所以我们需要统一返回的错误。异常处理允许它返回统一的异常格式。
问题剖析如果您只关注解决方案,可以直接跳至解决方案模块!
OAuth2Exception异常处理在Oauth2认证服务器中,认证逻辑最终会调用TokenEndpoint#postAccessToken()方法,认证过程中一旦发生OAuth2Exception,就会被handleException()捕获。下图是用户密码异常时的debug截图:
捕获OAuth2Exception 后,身份验证服务器将调用WebResponseExceptionTranslator#translate() 方法来翻译该异常。
默认的翻译处理实现类是DefaultWebResponseExceptionTranslator。处理完成后,会调用handleOAuth2Exception()方法,将处理后的异常返回给前端。这就是我们之前看到的异常效果。
处理方法熟悉Oauth2例程的同学应该知道如何处理此类异常,就是“自定义一个异常翻译类,返回我们需要的自定义格式,然后注入到认证服务器中”。
但这个处理逻辑只能解决OAuth2Exception异常,即前言中的“授权模式异常”和“账户密码异常”,并不能解决我们客户端的异常。
客户端异常处理客户端认证异常发生在过滤器ClientCredentialsTokenEndpointFilter中,该过滤器有一个后期添加的失败处理方法,最终将异常交给OAuth2AuthenticationEntryPoint所谓的认证入口点进行处理。执行顺序如下:
然后跳转到父类的AbstractOAuth2SecurityExceptionHandler#doHandle()进行处理:
最后,DefaultOAuth2ExceptionRenderer#handleHttpEntityResponse()方法将异常输出到客户端。
处理方法通过上面的分析,我们知道客户端认证失败异常是转入OAuth2AuthenticationEntryPoint获取响应结果的过滤器ClientCredentialsTokenEndpointFilter。这种情况下,我们可以重写ClientCredentialsTokenEndpointFilter,然后使用自定义的AuthenticationEntryPoint来替换原生的OAuth2AuthenticationEntryPoint。在自定义的AuthenticationEntryPoint 中处理我们想要的异常数据。
解决方案为了解决上面的异常,我们首先需要针对不同的异常编写错误码:ReturnCode.java
CLIENT_AUTHENTICATION_FAILED(1001,'客户端身份验证失败'),USERNAME_OR_PASSWORD_ERROR(1002,'用户名或密码错误'),UNSUPPORTED_GRANT_TYPE(1003,'不支持的身份验证模式');OAuth2Exception异常@Slf4jpublicclassCustomWebResponseExceptionTranslatorimplementsWebResponseExceptionTranslator{@OverridepublicResponseEntitytranslate(Exceptione)throwsException{log.error('身份验证服务器异常',e);ResultDataresponse=resolveException(e);returnnewResponseEntity(response,HttpStatus.valueOf(response.getHttpStatus())); }/***构造返回异常*@parameException*@return*/privateResultDataresolveException(Exceptione){//初始值500ReturnCodereturnCode=ReturnCod e.RC500;inthttpStatus=HttpStatus.UNAUTHORIZED.value();//不支持的认证方式if(einstanceofUnsupportedGrantTypeException ){returnCode=ReturnCode.UNSUPPORTED_GRANT_TYPE;//用户名或密码异常}elseif(einstanceofInvalidGrantException){returnCode=ReturnCode.USERNAME_OR_PASSWORD_ERROR;}ResultDatafailResponse=ResultData.fail(returnCode.getCode(),returnCode.getMessage());failResponse.setHttpStatus (httpStatus);returnfailResponse;}}然后在认证服务器配置类中注入自定义异常翻译类
@Overridepublicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints) throwsException{//如果需要使用refresh_token模式,需要注入userDetailServiceendpoints.authenticationManager(this.authenticationManager).userDetailsService(userDetailServi ce)//注入tokenGranter.tokenGranter(tokenGranter);//注入自定义令牌服务。如果不使用自定义tokenService,需要将tokenServce中的配置移到这里//.tokenServices(tokenServices());//自定义异常转换类endpoints.exceptionTranslator(newCustomWebResponseExceptionTranslator());}客户端异常重写客户端身份验证过滤器,不使用默认的OAuth2AuthenticationEntryPoint 来处理异常
publicclassCustomClientCredentialsTokenEndpointFilterextendsClientCredentialsTokenEndpointFilter{privatefinalAuthorizationServerSecurityConfigurerconfigurer;privateAuthenticationEntryPointauthenticationEntryPoint;publicCustomClientCredentialsTokenEndpointFilter(AuthorizationServerSecurityConfigurerconfigurer){this.configurer=configurer;}@OverridepublicvoidsetAuthenticationEntryPoint(AuthenticationEntryPointauthenticationEntryPoint){super.setAuthenticat ionEn tryPoint(null);this.authenticationEntryPoint=authenticationEntryPoint;}@OverrideprotectedAuthenticationManagergetAuthenticationManager(){returnconfigurer.and() .getSharedObject(AuthenticationManager.class);}@Overridepublicvo idafterPropertiesSet(){setAuthenticationFailureHandler((请求,响应,e)-authenticationEntryPoint.commence(请求,响应,e));setAuthenticationSuccessHandler((请求,响应,身份验证)-{}) ;}}将异常处理逻辑注入到身份验证服务器中。自定义异常返回结果。 (代码在AuthorizationServerConfig中)
@BeanpublicAuthenticationEntryPointauthenticationEntryPoint(){return(request,response,e)-{response.setStatus(HttpStatus.UNAUTHORIZED.value());ResultDataresultData=ResultData a.fail(ReturnCode.CLIENT_AUTHENTICATION_FAILED.getCode(),ReturnCode.CLIENT_AUTHENTICATION_FAILED.getMessage() );WebUtils.writeJson(response,resultData);};}修改身份验证服务器配置并注入自定义过滤器
@Overridepublicvoidconfigure(AuthorizationServerSecurityConfigurersecurity)throwsException{CustomClientCredentialsTokenEndpointFilterendpointFilter=newCustomClientCredentialsTokenEndpointFilter(security);endpointFilter.afterPropertiesSet();endpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint());security.addTokenlterEndpointAuthenticationFi(endpointFilter);security.authenticationEntryPoint(authenticationEntryPoint())/*.allow表单身份验证ForClients() *///如果使用form认证,需要添加.tokenKeyAccess('permitAll()').checkTokenAccess('isAuthenticated()');} 此时需要删除allowFormAuthenticationForClients()配置,否则自定义过滤器将不会生效。至于为什么不行,看源码就可以知道。
测试授权模式错误
账号密码错误
客户端错误
以上,希望对您有所帮助!
END,本文到此结束,如果可以帮助到大家,还望关注本站哦!
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/6820.html
用户评论
好题目,想学习一下 Spring Cloud Alibaba 的 OAuth2 认证
有6位网友表示赞同!
感觉这篇文章内容很有实用性,自定义异常真是个好的解决方案
有15位网友表示赞同!
终于有人讲了这个主题!我一直想尝试自己定制 OAuth2 认证流程
有20位网友表示赞同!
在实际开发中遇到过类似问题,感谢作者分享经验
有9位网友表示赞同!
51CTO 上的文章质量一直不错,期待深入学习作者的讲解
有12位网友表示赞同!
做 SpringCloud Alibaba 的项目,OAuth2 是必不可少的模块吧?
有18位网友表示赞同!
自定义异常可以提升系统的容错性,这篇文章太有价值了!
有17位网友表示赞同!
最近在研究 OAuth2,希望这篇文章能给我带来一些启发
有7位网友表示赞同!
Spring Cloud Alibaba 越来越强大,这个认证方案让我很感兴趣
有16位网友表示赞同!
学习 Spring Boot 和微服务的时候,OAuth2 也经常用到
有16位网友表示赞同!
作者的讲解一定很专业,希望能详细地介绍一下自定义异常的实现过程
有17位网友表示赞同!
这篇文章刚好能解决我现在遇到的问题,太棒了!
有7位网友表示赞同!
对于 OAuth2 认证还不太了解,这篇文章可以帮助我入门学习
有19位网友表示赞同!
喜欢看关于 Spring Cloud 的实践案例,希望这篇文章能提供一些参考思路
有12位网友表示赞同!
分享这种自定义异常的经验非常有意义,可以让其他开发者更快上手
有9位网友表示赞同!
技术细节讲解到位,我很期待作者的深入分享
有18位网友表示赞同!
OAuth2 认证在微服务架构中很重要,这个主题很有价值
有18位网友表示赞同!
可以从这篇文章学习到一些解决实际问题的技巧
有11位网友表示赞同!
喜欢51CTO的文章风格,内容实用性强,容易理解
有16位网友表示赞同!
感谢作者分享宝贵的知识和经验!
有7位网友表示赞同!