Google OAuth会处理已撤销的授权

时间:2014-06-16 08:22:58

标签: java google-calendar-api google-oauth

我一直在使用 Google OAuth 让用户授权访问我的Web应用程序的日历服务。成功3-legged auth flow后,我将所有用户的凭据存储在应用服务器上的公共文件中。下次应用程序需要使用该服务时,它将检查凭据是否存在,如果是,则认为它们是有效的

代码就像那样

@Override
public void _authorize(String userId) throws IOException {

    // Check if user has already authorised the service.
    Credential credents = flow.loadCredential(userId);

    // Checking if the given user is not authorized
    if (credents == null) {

        //Create credentials now. user will be redirected to authorise 

        try {
            //Creating a LocalServer Receiver
            // Getting the redirect URI
            // Creating a new authorization URL
            // Setting the redirect URI
            // Building the authorization URL
            // Receiving authorization code
            // Exchanging it for an access token

            // Storing the credentials for later access
            credents = flow.createAndStoreCredential(response, id);

        } finally {
            // Releasing resources
        }
    } else {
        // Assume the credentials are valid. so there's nothing left to do here, let's get that client
        //Update: Nooooooot! the user might have revoked the authorization, so credents != null BUT they are invalid
        //TODO: handle an Exception here, and manage the revoked credentials 
    }

    // Setting up the calendar service client
    client = new com.google.api.services.calendar.Calendar.Builder(httpTransport, jsonFactory, credents).setApplicationName(APPLICATION_NAME)
            .build();

}

只要用户永远不会改变主意,这种方法就可以了。但是,如果用户使用Google帐户安全选项决定 manually revoke 授权,则com.google.api.services.calendar.Calendar检索将失败。

我的问题是

  1. 如果凭据仍然有效,检查尝试使用之前是否有办法? 否则,我只能猜测无法获取客户端对象,唯一的方式让我的门户网站意识到凭据不再有效?
  2. 如何处理无效/撤销的凭据?我应该打电话给flow.createAndStoreCredential,他们会被覆盖吗?或者我必须先删除旧的? (怎么样?)

4 个答案:

答案 0 :(得分:2)

您可以使用refreshToken()方法。见例:

// Fetch credential using the GoogleAuthorizationCodeFlow
GoogleAuthorizationCodeFlow authorizationCodeFlow;
Credential credential = authorizationCodeFlow.loadCredential(userId);
if (credential != null) {
    try {
        // refresh the credential to see if the refresh token is still valid
        credential.refreshToken();
        System.out.println("Refreshed: expires in: " + credential.getExpiresInSeconds());
    } catch (TokenResponseException e) {
        // process exception here.
        // This will catch the Exception.
        // This Exception contains the HTTP status and reason etc.
        // In case of a revoke, this will throw something like a 401 - "invalid_grant"
        return;
    }
} else {
    // No credential yet known.
    // Flow for creating a new credential here
}

修改 如果您确实有一个无效的刷新令牌并且想要续订它,那么您需要重复您在第一时间所做的步骤以获取凭据。所以:

  • 生成新的授权网址
  • 将用户重定向到它
  • 用户接受同意屏幕
  • 将重定向中的授权码捕获回您的应用
  • 使用授权码
  • 向Google请求新令牌
  • 使用Google的回复
  • 创建并存储新的凭据

无需删除旧凭据。但如果你想明确这样做,那就有可能。 类似的东西:

// This userId is obviously the same as you used to create the credential
String userId = "john.doe";
authorizationCodeFlow.getDataStore().delete(userId);

答案 1 :(得分:1)

您可以使用端点https://www.googleapis.com/oauth2/v1/tokeninfo来确定OAuth2令牌是否仍然有效。有关详细信息,请参阅OAuth2 guide

答案 2 :(得分:0)

回答第一个问题:

使用服务对象从Google日历中检索日历项时,会自动验证令牌。当它们无效时,它们将自动刷新,并存储在您提供给流程的数据存储区中。

这也可以手动完成。令牌有效期为3600秒(一小时)。检索令牌时,您将获得此值以及发布时的时间戳。您可以手动确定令牌是否有效。如果无效,请调用以下异步方法。

await credents.RefreshtokenAsync(CancellationToken.None);

此功能可获取新鲜令牌,并将其存储在您提供的数据存储中。

答案 3 :(得分:0)

使用tokeninfo检查令牌以及令牌是否无效: - 从数据存储中删除凭据 - 调用新的身份验证

protected void doGet(HttpServletRequest request,HttpServletResponse response)抛出IOException,ServletException {         UserService userService = UserServiceFactory.getUserService();

    if (userService.isUserLoggedIn()) {
        User user = userService.getCurrentUser();
        log.info(String.format("LoggedUser: %s %s", user.getEmail(), user.getUserId()));
        Credential credential = this.getCredential();
        Tokeninfo tokenInfo = OAuth2Utils.getTokenInfo(credential, null);
        if (tokenInfo != null)
            log.info(String.format("Token expires in: %d", tokenInfo.getExpiresIn()));
        else {
            OAuth2Utils.deleteCredential(user.getUserId());
            response.sendRedirect(request.getRequestURI()); // recall this servlet to require new user authorization
            return;
        }

}

public static Tokeninfo getTokenInfo(Credential credential,String accessToken){         Oauth2 service = new Oauth2.Builder(new NetHttpTransport(),Constant.JSON_FACTORY,credential).setApplicationName(Constant.APP_NAME).build();         Tokeninfo tokenInfo = null;         尝试{             tokenInfo = service.tokeninfo()。setAccessToken(accessToken == null?credential.getAccessToken():accessToken).execute();         } catch(IOException e){             log.warning(“发生错误:”+ e);         }         return tokenInfo; }