Spring 5,OAuth2与Google刷新访问令牌401后返回



我有简单配置的应用

spring.security.oauth2.client.registration.google.clientId=xyz
spring.security.oauth2.client.registration.google.clientSecret=xyz
spring.security.oauth2.client.registration.google.scope=email,profile,openid,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/spreadsheets

我使用登录http://localhost:8080/oauth2/authorization/google并正常保存到谷歌日历。

获取访问令牌看起来像:

private String getAccessToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String accessToken = null;
if (authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
String clientRegistrationId = oauthToken.getAuthorizedClientRegistrationId();
OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
clientRegistrationId, oauthToken.getName());
accessToken = client.getAccessToken().getTokenValue();
}
return accessToken;
}

OAuth2AuthorizedClient包含刷新令牌。

但在1小时后访问令牌过期,我不知道如何刷新它。没有重新登录。

https://developers.google.com/calendar/v3/errors#401_invalid_credentials表示

使用长期刷新令牌获取新的访问令牌。

我发现了这个带有刷新令牌的Spring Google OAuth2,但对我不起作用。

A也在401之后重新登录消息,但它不方便用户使用。

你能帮我吗?提前谢谢。

感谢DaImTo的提示。

我更改了的凭据使用

Credential credential = new GoogleCredential().setAccessToken(tokenUtils.getAccessToken());

private Calendar getClient() throws GeneralSecurityException, IOException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
Credential credential = new GoogleCredential.Builder()
.setJsonFactory(JSON_FACTORY)
.setTransport(httpTransport)
.setClientSecrets(clientId, clientSecret)
.build()
.setAccessToken(tokenUtils.getAccessToken())
.setRefreshToken(tokenUtils.getRefreshToken());
return new Calendar.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName("appname").build();
}

它起作用了!

但只有当设置了值为select_accountconsentprompt时,应用程序才会接收到Refresh Token。值为none或不为prompt时,刷新令牌始终为空(access_type=offline(。

它也不是用户友好的,因为应用程序用户每次都必须选择谷歌帐户。。。

你知道一些变通办法吗?

编辑:

public class TokenUtils {
private final OAuth2AuthorizedClientService authorizedClientService;
public TokenUtils(OAuth2AuthorizedClientService authorizedClientService) {
this.authorizedClientService = authorizedClientService;
}
public String getAccessToken() {
OAuth2AuthorizedClient client = getClient();
return client.getAccessToken().getTokenValue();
}
public String getRefreshToken() {
OAuth2AuthorizedClient client = getClient();
return client.getRefreshToken().getTokenValue();
}
public OAuth2AuthorizedClient getClient() {
OAuth2AuthenticationToken oauthToken = getOAuthToken();
return authorizedClientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName());
}
private OAuth2AuthenticationToken getOAuthToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {
return (OAuth2AuthenticationToken) authentication;
}
throw new SecurityException("Authentication is not OAuth2AuthenticationToken");
}
}

编辑2:

http
.oauth2Login()
.successHandler(new RedirectToPrevAuthSuccessHandler())
.userInfoEndpoint()
.oidcUserService(addRolesOidcUserService);
.oidcUserService(addRolesOidcUserService)
.and()
.authorizationEndpoint()
.authorizationRequestResolver(new AddParamsRequestResolver(
this.clientRegistrationRepository))
;

public class AddParamsRequestResolver implements OAuth2AuthorizationRequestResolver {
private final OAuth2AuthorizationRequestResolver defaultAuthorizationRequestResolver;
public AddParamsRequestResolver(ClientRegistrationRepository clientRegistrationRepository) {
this.defaultAuthorizationRequestResolver =
new DefaultOAuth2AuthorizationRequestResolver(
clientRegistrationRepository,
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
OAuth2AuthorizationRequest authorizationRequest =
this.defaultAuthorizationRequestResolver.resolve(request);
if (authorizationRequest != null) {
return addParams(authorizationRequest);
}
return null;
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
OAuth2AuthorizationRequest authorizationRequest =
this.defaultAuthorizationRequestResolver.resolve(
request, clientRegistrationId);
if (authorizationRequest != null) {
return addParams(authorizationRequest);
}
return null;
}
private OAuth2AuthorizationRequest addParams(
OAuth2AuthorizationRequest authorizationRequest) {
Map<String, Object> additionalParameters =
new LinkedHashMap<>(authorizationRequest.getAdditionalParameters());
additionalParameters.put("access_type", "offline");
additionalParameters.put("prompt", "consent");
//    additionalParameters.put("prompt", "select_account");
//    additionalParameters.put("prompt", "login");
return OAuth2AuthorizationRequest.from(authorizationRequest)
.additionalParameters(additionalParameters)
.build();
}

最新更新