首页 > 解决方案 > 如何从 OAuth2 客户端应用程序中的授权服务器获取属于访问令牌响应的一部分的附加信息

问题描述

访问令牌响应

{
    "access_token": "fd515395-ab03-4cc5-9ba4-03c42bdfdf189b73",
    "token_type": "bearer",
    "refresh_token": "176ee948-ebdc-4d51-9768-08aa1dfdd081442",
    "expires_in": 10799,
    "scope": "user_info",
    "instance_url": "https://xxxx.xxx.com/xx-xxx-service"
}

我已经尝试如下但没有运气

@RequestMapping("/securedPage")
    public String securedPage( Model model, OAuth2AuthenticationToken authToken ) {

        OAuth2AuthorizedClient client = clientService.loadAuthorizedClient( authToken.getAuthorizedClientRegistrationId(), authToken.getName() );

        OAuth2AccessToken accessToken = client.getAccessToken();

        System.out.println( accessToken.getTokenValue() );
        System.out.println( accessToken.getExpiresAt() );
        System.out.println( client.getPrincipalName() );
        System.out.println( client.getRefreshToken().getTokenValue() );

        // Get "instance_url" here

        return "securedPage.html";
}

标签: javaspringspring-securityspring-security-oauth2

解决方案


我看到了 3 种可能的方法来获得结果:

  1. 使用注入Principal对象。对于 Spring OAuth2,它是用 class 实现的OAuth2Authentication。您可以在此对象中找到大部分信息 - 在details, userAuthentication, 中storedRequest。检查它,你会看到你需要什么。

  2. 使用身份验证请求直接获取所有必需的参数:

服务方式:

var resourceDetails = ((OAuth2RestTemplate) restTemplate).getResource();
var headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setBasicAuth(resourceDetails.getClientId(), resourceDetails.getClientSecret());
var form = new LinkedMultiValueMap<String, String>();
form.add("grant_type", "password");
form.add("username", "<username>");
form.add("password", "<password>");
var request = new HttpEntity<>(form, headers);
var response = restTemplate.postForObject(resourceDetails.getAccessTokenUri(), request, LinkedHashMap.class);

该对象response包含访问令牌响应中的所有参数。

一件事-您需要使用特定restTemplate的下一个:

var resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setClientId("<clientId>");
resourceDetails.setClientSecret("<clientSecret>");
resourceDetails.setAccessTokenUri("<accessTokenUri>");
resourceDetails.setScope("<scopes>");
resourceDetails.setAuthenticationScheme(AuthenticationScheme.header);
resourceDetails.setGrantType("client_credentials");
var restTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext());
var requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(10000);
requestFactory.setConnectionRequestTimeout(10000);
requestFactory.setReadTimeout(10000);
restTemplate.setRequestFactory(requestFactory);
var tokenProvider = new ClientCredentialsAccessTokenProvider();
tokenProvider.setRequestFactory(requestFactory);
restTemplate.setAccessTokenProvider(new AccessTokenProviderChain(Arrays.<AccessTokenProvider>asList(
        new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(),
        new ResourceOwnerPasswordAccessTokenProvider(), tokenProvider)));
  1. 在授权服务器上生成一个对象,并用一个类似的 restTemplate 响应它给客户端。这是一种不受欢迎的方法,但也可以实施。

推荐阅读