最近工作的一个项目中需要调用第三方提供的API获取数据,该API接口采用的授权方式是OAuth2,授权类型采用client_crdentials。鉴于Spring框架完善的生态系统我们直接采用了spring-security-oauth2 框架中提供的OAuth2客户端能力。现将使用框架过程中遇到的几个问题记录,供以后参考,以希望其他开发的同学能够避免踩坑。
(1)
关于security.oauth2.client.*几个相关配置项容易混淆
- .security.oauth2.client.authentication-scheme
这个配置项主要指定访问API时传输bearer token的方式,有四个可选值
header,query,form,none,
默认值为:header,表示在HTTP头中传输
- .security.oauth2.client.client-authentication-scheme
这个配置项主要指定进行客户端认证时传输client_id,client-secret的方式,同样有四
个可选值header,query,form,none,
默认值为:header,表示在HTTP头中传输
- .security.oauth2.client.grant-type
这个配置项主要指定进行客户端获取access_token的授予类型,有四个可选值
authorization_code,client_credentials,password,implicit
Spring OAuth2框架默认会采用authorization_code (授权码授予)access_token方式
这里一定要记得根据API的access_token授予类型配置,例如我们访问的API实现的是
client_crdentials 这种授予类型因此要配置成:
security.oauth2.client.grant-type=client_crdentials
(2)
关于配置 OAuth2RestTemplate BEAN实例化时要传入正确的OAuth2资源保护类型
public OAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {
super();
if (resource == null) { //不能传空的
throw new IllegalArgumentException("An OAuth2 resource must be supplied.");
}
this.resource = resource;
this.context = context;
[color=red]setErrorHandler(new OAuth2ErrorHandler(resource))[/color];//设置出错处理器
}
Spring OAuth2框架默认会使用AuthorizationCodeResourceDetails来映射配置项,例如果想要使用client_crdentials,就必须采用ClientCredentialsResourceDetails,这个类必须要自己实例化,否则框架默认会传AuthorizationCodeResourceDetails给你,这个地方要特别注意。
@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();//根据资源的访问授预类型来选取
....
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, oauth2ClientContext);
....
}
探究一下原码OAuth2RestTemplate容易发现,它内部委托AccessTokenProvider 获取access_token,内部管理着一AccessTokenProviderChain,如下所示:
private AccessTokenProvider accessTokenProvider = new AccessTokenProviderChain(Arrays.<AccessTokenProvider> asList(
new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(),
new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider()));
在acquireAccessToken方法中委托
protected OAuth2AccessToken acquireAccessToken(OAuth2ClientContext oauth2Context){
....
accessToken = accessTokenProvider.obtainAccessToken(resource, accessTokenRequest);
....
}
AccessTokenProviderChain 使用 List<AccessTokenProvider> chain 集合中的每一种AccessTokenProvider尝试根据OAuth2ProtectedResourceDetails的类型调用如下具体AccessTokenProvider的实现类完成access_token的获取,同样有4个实现类:1.ClientCredentialsAccessTokenProvider
2.AuthorizationCodeAccessTokenProvider
3.ImplicitAccessTokenProvider
4.ResourceOwnerPasswordAccessTokenProvider
每个实现都有一个supportsResource 方法检查配置的OAuth2资源保护类型自己是否能处理,以ClientCredentialsAccessTokenProvider为例
public boolean supportsResource(OAuth2ProtectedResourceDetails resource) {
return resource instanceof ClientCredentialsResourceDetails
&& "client_credentials".equals(resource.getGrantType());
}
(3)
OAuth2RestTemplate 默认对错误的处理可能导致API返回的业务错误信息我们无法获取
在前面的代码片段里我们知道OAuth2RestTemplate 把出错处理交给了类OAuth2ErrorHandler处理,这个类有一个重要的方法来判断响应状态码是否是4XX,5XX:
public boolean hasError(ClientHttpResponse response) throws IOException {
return HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series())
|| this.errorHandler.hasError(response);
}
然后OAuth2ErrorHandler又交给了默认的 DefaultResponseErrorHandler 来处理,该个类会将5xx的错误包装成HttpServerErrorException 走了WEB的出错理机制。因此通过ResponseEntity无法获业务错误信息。
此时就需要定制OAuth2ErrorHandler,主要是重写hasError方法,如下所示:
public class NoOpResponseErrorHandler extends OAuth2ErrorHandler {
public NoOpResponseErrorHandler(OAuth2ProtectedResourceDetails resource) {
super(resource);
}
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getStatusCode().equals(HttpStatus.UNAUTHORIZED) ||
response.getStatusCode().equals(HttpStatus.FORBIDDEN);
}
}
然后通过调用OAuth2RestTemplate 的 setErrorHandler()方法注入
(4)关于Error creating bean with name 'scopedTarget.oauth2ClientContext' despite defining RequestContextListener 异常
通过在配置类中添加
@Bean
@Order(0)
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
或在
web.xml文件中添加片段
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
总之想要快速处理问题就需要我们对其框架原理有基本的理解和研究,这样才能少走弯路
最后推荐几个链接,大家可以去了解一下
(1)Spring Boot and OAuth2
https://spring.io/guides/tutorials/spring-boot-oauth2/
(2)Protecting REST API with OAuth2
http://stackmirror.caup.cn/page/s18eicq1kmrc
分享到:
相关推荐
8. **安全考虑**:如果REST服务需要身份验证,可以使用OAuth2、JWT等方式,将令牌添加到请求头中。Spring Security可以帮助我们轻松实现这一点。 9. **监控和日志**:为了跟踪和优化客户端性能,可以集成Spring ...
2. **RESTful API调用**:如果U9接口采用REST(Representational State Transfer)风格,那么Java开发者可能需要使用JAX-RS(Java API for RESTful Web Services)或者Spring的RestTemplate来构造HTTP请求,如GET、...
1. **HTTP通信库**:项目可能使用了如Apache HttpClient、OkHttp或Spring的RestTemplate等库来发起HTTP请求,与服务器进行数据交换。这些库使得开发者能够方便地构建GET、POST等不同类型的HTTP请求,并处理响应数据...
清华大学2024级化学生物学专业本科培养方案
朗读程序代码
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
数字播放声音程序VB.NET新源代码
基于蒙特卡洛法的风光场景生成与概率距离快速削减算法研究,MATLAB代码 风光场景生成 场景削减 概率距离削减法 蒙特卡洛法 MATLAB:基于概率距离快速削减法的风光场景生成与削减方法 参考文档:《含风光水的电厂与配电公司协调调度模型》完全复现场景削减部分 仿真平台:MATLAB平台 代码具有一定的深度和创新性,注释清晰 主要内容:风电、光伏以及电价场景不确定性模拟,首先由一组确定性的方案,通过蒙特卡洛算法,生成50种光伏场景,为了避免大规模光伏场景造成的计算困难问题,采用基于概率距离快速削减算法的场景削减法,将场景削减至5个,运行后直接给出削减后的场景以及生成的场景,并给出相应的概率,可移植以及可应用性强。 ,MATLAB; 风光场景生成; 场景削减; 概率距离削减法; 蒙特卡洛法; 深度创新性; 注释清晰; 虚拟电厂与配电公司协调调度模型; 风电光伏电价场景不确定性模拟; 概率距离快速削减算法。,基于MATLAB的场景生成与削减技术:风光场景概率距离快速削减法研究与应用
1、文件内容:felix-utils-1.2.0-5.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/felix-utils-1.2.0-5.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea 数据库:MySql8.0 部署环境:Tomcat(建议用 7.x 或者 8.x 版本),maven 数据库工具:navicat
1、文件内容:exchange-bmc-os-info-1.8.18-11.el7_9.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/exchange-bmc-os-info-1.8.18-11.el7_9.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea 数据库:MySql8.0 部署环境:Tomcat(建议用 7.x 或者 8.x 版本),maven 数据库工具:navicat
1、文件内容:exec-maven-plugin-javadoc-1.2.1-13.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/exec-maven-plugin-javadoc-1.2.1-13.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea 数据库:MySql8.0 部署环境:Tomcat(建议用 7.x 或者 8.x 版本),maven 数据库工具:navicat
HarmonyOS NEXT学习资料(鸿蒙next)
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
论文写作与科技前沿等(2025.01.23)
1、文件内容:farstream-0.1.2-8.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/farstream-0.1.2-8.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
2025最新网络安全建设与网络社会治考试题库及答案.doc
1小钢琴程序QZQ2024-7-30-20-45