如何使用 spring-boot-starter-oauth2-client 执行刷新

How to perform a refresh with spring-boot-starter-oauth2-client

我正在使用 spring-boot-starter-oauth2-client 通过 Google 验证我的用户。这很好用,我可以按预期登录并获得有效访问和刷新令牌。

我正在这样创建访问令牌:

public class TokenServiceImpl implements TokenService {

    private final OAuth2AuthorizedClientService clientService;

    @Override
    public GoogleCredentials credentials() {
        final var accessToken = getAccessToken();

        return getGoogleCredentials(accessToken);
    }

    private GoogleCredentials getGoogleCredentials(String accessToken) {

        return GoogleCredentials
                .newBuilder()
                .setAccessToken(new AccessToken(accessToken, null))
                .build();
    }

    private String getAccessToken() {
        final var oauthToken = (OAuth2AuthenticationToken) SecurityContextHolder.getContext().getAuthentication();

        return clientService.loadAuthorizedClient(
                oauthToken.getAuthorizedClientRegistrationId(),
                oauthToken.getName()).getAccessToken().getTokenValue();
    }
}

令牌最终在 Google 照片 API 客户端中使用

    private PhotosLibraryClient getClient() {
        
        final var settings =
                PhotosLibrarySettings
                        .newBuilder()
                        .setCredentialsProvider(FixedCredentialsProvider.create(tokenService.credentials()))
                        .build();

        return PhotosLibraryClient.initialize(settings);
    }

问题是令牌将在短时间后过期,我想刷新它以使其保持活动状态。

我不确定我可以使用哪种方法模式来执行此操作,而不必编写整个 OAuth 流程(违背 Spring oauth2-client 之类的目的)。

到目前为止,我的应用程序中没有其他 token/security/filter 逻辑。

我只需要手动写出来,还是有其他方法可以做到这一点?

OAuth2AuthorizedClientManager 将负责为您刷新访问令牌,前提是您获得了刷新令牌和访问令牌。 OAuth2AuthorizedClientManager 的文档位于

https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client

配置 OAuth2AuthorizedClientManager 时,请确保您已在 OAuth2AuthorizedClientProvider 中包含 refreshToken...

@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientRepository authorizedClientRepository) {

    OAuth2AuthorizedClientProvider authorizedClientProvider =
            OAuth2AuthorizedClientProviderBuilder.builder()
                    .authorizationCode()
                    .refreshToken()
                    .build();

    DefaultOAuth2AuthorizedClientManager authorizedClientManager =
            new DefaultOAuth2AuthorizedClientManager(
                    clientRegistrationRepository, authorizedClientRepository);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    // Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
    // map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
    authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());

    return authorizedClientManager;
}

然后您使用 OAuth2AuthorizedClientManager 获取访问令牌。来自 spring doco 的示例如下...

@Controller
public class OAuth2ClientController {

    @Autowired
    private OAuth2AuthorizedClientManager authorizedClientManager;

    @GetMapping("/")
    public String index(Authentication authentication,
                        HttpServletRequest servletRequest,
                        HttpServletResponse servletResponse) {

        OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
                .principal(authentication)
                .attributes(attrs -> {
                    attrs.put(HttpServletRequest.class.getName(), servletRequest);
                    attrs.put(HttpServletResponse.class.getName(), servletResponse);
                })
                .build();
        OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);

        OAuth2AccessToken accessToken = authorizedClient.getAccessToken();

        ...

        return "index";
    }
}

如果当前的accessToken已经过期,这将自动使用之前获得的refreshToken请求一个新的accessToken。