java - 如何配置必须使用“密码”授权类型从授权服务器请求令牌的客户端 Java 应用程序?
问题描述
我需要使用 Maven 实现客户端 Java 应用程序,该应用程序从资源服务器发出请求。为了授权请求,必须在请求的标头中提供不记名令牌。要获得令牌,必须先完成另一个请求。服务器为我提供了发出令牌请求所需的所有参数:client_id、client_secret、用户名、密码等。令牌请求的 grant_type 是“密码”。
服务器基于 GraphQL,因此我使用以下 Maven 插件来生成执行 GraphQL 查询的 Java 类: https ://github.com/graphql-java-generator/graphql-maven-plugin-project
他们提供了有关如何“访问 OAuth2 GraphQL 服务器”的教程: https ://graphql-maven-plugin-project.graphql-java-generator.com/client_oauth2.html
正如他们在教程中提到的,为了连接到 OAuth 服务器,我必须使用 Spring。本教程解释了如何访问使用“client_credentials”授权类型的服务器。我不熟悉spring和spring-security,所以我没有设法将我的Spring客户端配置为'password'授权类型(我所做的只是在application.properties中将grant_type从'client_credentials'更改为'password') . 需要在哪里配置用户名和密码?我需要做哪些额外的配置?没有春天有没有办法做到这一点?我想要获得的是从授权服务器请求令牌并(在后台)将令牌添加到资源请求的方式。
以下是我遵循教程的一段代码:
@SpringBootApplication(scanBasePackageClasses = { MinimalSpringApp.class, GraphQLConfiguration.class})
public class MinimalSpringApp implements CommandLineRunner
{
/**
* The executor, that allows to execute GraphQL queries. The class name is the one defined in the GraphQL schema.
*/
@Autowired
QueryExecutor queryExecutor;
public static void main( String[] args )
{
SpringApplication.run( MinimalSpringApp.class, args );
}
/**
* This method is started by Spring, once the Spring context has been loaded. This is run, as this class implements
* {@link CommandLineRunner}
*/
@Override
public void run( String... args ) throws Exception
{
// Create query
GraphQLRequest softwareTechnologyRequest = queryExecutor.getSoftwareTechnologyGraphQLRequest( "{ id name }" );
SoftwareTechnologyFilter filter = new SoftwareTechnologyFilter();
// Execute query
List<SoftwareTechnology> technologies =
queryExecutor.softwareTechnology( softwareTechnologyRequest, filter, 0, "", 1000, "", 0,
Collections.emptyList() );
System.out.println( technologies );
}
@Bean
ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunction(
ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("provider_test");
return oauth;
}
当我运行应用程序时,它会引发由“401 Unauthorized from POST”引起的 IllegalStateException。
解决方案
解决了
我需要创建自己的客户端管理器 bean,其中设置了用户名和密码。在“资源所有者密码凭据”部分的 Spring 官方文档中有一个示例: https ://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle/#oauth2client
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager( ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService)
{
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder().password().refreshToken().build();
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService );
authorizedClientManager.setAuthorizedClientProvider( authorizedClientProvider );
authorizedClientManager.setContextAttributesMapper( contextAttributesMapper() );
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>> contextAttributesMapper()
{
return authorizeRequest -> {
Map<String, Object> contextAttributes = new HashMap<>();
contextAttributes.put( OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username" );
contextAttributes.put( OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password" );
return Mono.just(contextAttributes);
};
}
然后需要修改 graphql java generator plugin tutorial 中的 bean,以便使用提供的客户端管理器:
@Bean
ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunction(
ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
authorizedClientManager);
oauth.setDefaultClientRegistrationId("provider_test");
return oauth;
}
推荐阅读
- sql - 使用循环更新耗时太长
- virtual-machine - 如何将我的虚拟机共享给其他人?
- javascript - 为什么使用 express 将数组发送到前端时 Json stringify 有帮助?
- objective-c - iOS 13 用户的 NSNumberFormatter 忽略 setRoundingIncrement
- python - 如何在小数点后附加4个数字的浮点数?
- java - Intellij Idea 2019.2 更新后在 Intellij 中导入项目时没有下一个和上一个按钮
- php - 未发送来自表单的变量 $message 内容传递
- python - 使用 Python 从 excel 数据构建 XML
- javascript - 如何使用 for 循环将 Json 对象推送到 Json 数组?
- reactjs - 我在 componentDidUpdate 中的 prevProps 和 current props 是一样的,而我正在更新状态