首页 文章

OAuth2RestTemplate承载令牌类型

提问于
浏览
2

我正在将Spring Security OAuth2与OAuth2RestTemplate一起使用,以实现OAuth 2.0安全REST API的客户端 . 流程通过以下步骤成功获取访问令牌:

response.statusCode = 200
response.body = {"access_token":"9b90f8a84b939b8437a4fbaa8fff0052839cf6f5","expires_in":3600,"token_type":"bearer","scope":" read write","refresh_token":"e164f317a1708c3664025e9e56ce605cfe710474”}

但是,当代码尝试使用OAuth2RestTemplate访问受保护资源时,响应不成功:

GET request for "https://redacted.com/api/v1/clients" resulted in 400 (Bad Request)

这是因为DefaultOAuth2RequestAuthenticator使用随access_token返回的token_type值(“bearer”)来形成对受保护资源的请求的Authentication头:

request.getHeaders().set("Authorization", String.format("%s %s", tokenType, accessToken.getValue()));

这会导致请求Authorization标头中的凭证字段以字符串“bearer”为前缀:

Request Header: "Authorization" "bearer a8f18cb3173c4cbbea44f4495dd5e5662156c391"

但是,根据OAuth 2.0承载令牌使用规范第2.1节“授权请求标头”字段,凭证字段的格式为:

credentials =“Bearer”1 * SP b64token

请注意,在规范中,“Bearer”是大写的 . 这意味着请求标头应为:

Request Header: "Authorization" "Bearer a8f18cb3173c4cbbea44f4495dd5e5662156c391"

显然,我们发送请求的提供商实施规范的范围很小,因为大写问题(“bearer”与“Bearer”)是导致受保护资源的请求失败的原因 . 当我更改DefaultOAuth2RequestAuthenticator以强制前缀为 Headers 大小写时,请求成功:

if ("bearer".equals(tokenType)) {
    tokenType = "Bearer";
}

Header key = Authorization values = Bearer 8efd4381f3470660291e700e4927012f288ad66c,
Sending GET request to https://redacted.com/api/v1/clients
Received "200 OK" response for GET request to https://redacted.com/api/v1/clients: [[{"id":"999999999","client_user_id":"a1b2c3d4e5f6"...

我真的不想拥有自己的Spring Security OAuth2分支来解决这个问题 . 这对任何人都有用吗?我错过了什么吗?

2 回答

  • 0

    事实证明,它实际上并不适用于很多人 . spring-security-oauth问题列表中存在一个未解决的问题(当前里程碑为2.2.1):

    Use OAuth2 token_type equal "Bearer" by default everywhere #457

    Headers 可能有点误导,但评论概述了这个问题并提出了解决方法,这些解决方案都是覆盖其中一个OAuth2令牌处理类的变体,以执行我对DefaultOAuth2RequestAuthenticator的修复 .

  • 1

    我通过这些代码解决了这个问题

    @Bean
    public OAuth2RestOperations restTemplate(){
    
        AccessTokenRequest accessTokenRequest = new DefaultAccessTokenRequest();
        OAuth2ClientContext oAuth2ClientContext = new DefaultOAuth2ClientContext(accessTokenRequest);
        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate( resource(),oAuth2ClientContext );
        oAuth2RestTemplate.setAuthenticator(new DefaultOAuth2RequestAuthenticator(){
            @Override
            public void authenticate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext clientContext, ClientHttpRequest request) {
                clientContext.setAccessToken(new DefaultOAuth2AccessToken(clientContext.getAccessToken()){
                    @Override
                    public String getTokenType() {
                        if ("bearer".equals(super.getTokenType())) {
                            return "Bearer";
                        }
                        return super.getTokenType();
                    }
                });
                OAuth2AccessToken accessToken = clientContext.getAccessToken();
                super.authenticate(resource, clientContext, request);
            }
        });
    

相关问题