Android中的Oauth2刷新令牌更新

Posted

技术标签:

【中文标题】Android中的Oauth2刷新令牌更新【英文标题】:Oauth2 refresh token renewal in Android 【发布时间】:2017-03-29 14:29:16 【问题描述】:

我正在开发一个 android 应用程序,它使用 Oauth2 令牌来获得授权以访问安全资源。我使用第三方平台作为身份验证服务器(使用 OpenId Connect)。基本上我的问题是我想处理过期的刷新令牌。

当前情景

我有一个NetUtils 类,它的作用类似于单例,并使用安全的休息模板管理我的所有请求。该 rest 模板使用请求包装器为每个请求注入所需的 Authorization 标头。 NetUtils 类处理令牌和超时,将它们保存在用户首选项中并在需要时刷新它们。

但是,当刷新令牌本身过期时,问题就出现了。当我使用授权代码流时,我需要打开一个 WebView 并将用户重定向到登录页面,但是当 NetUtils 类确定刷新令牌已过期时,我注意到它。理想情况下,应用程序会启动一个 WebView,用户将再次登录并执行存储的请求。这是我刷新访问令牌的代码:

private AccessToken refreshToken(String idClient, String clientSecret, AccessToken accessToken) 
    MultiValueMap<String, String> clientAuthenticationForm = new LinkedMultiValueMap<>();
    clientAuthenticationForm.add("grant_type", "refresh_token");
    clientAuthenticationForm.add("refresh_token", accessToken.getRefreshToken());
    clientAuthenticationForm.add("client_id", idClient);
    clientAuthenticationForm.add("client_secret", clientSecret);
    try 
        long lastClientRefresh = mPrefs.getLong(Preferences.LAST_LOGIN_TIME, Long.MIN_VALUE);
        boolean refreshTokenExpired = lastClientRefresh
                + TimeUnit.SECONDS.toMillis(accessToken.getRefreshExpiresIn()) < System
                .currentTimeMillis();
        if (!refreshTokenExpired) 
            return regularRestTemplate
                    .postForEntity(tokenUrl(), clientAuthenticationForm, AccessToken.class)
                    .getBody();
        else
            //How to cope with this?
            return null;
        
     catch (Exception ex) 
        Log.e(TAG, ex.getMessage(), ex);
        throw ex;
    

其他选择

例如,其他选择是使刷新令牌长期存在并在每次应用启动时刷新它。我不得不提一下,client_idclient_secret 目前正在应用程序中进行硬编码(尽管客户端凭据授予并不意味着在生产中启用,因此仍然需要提供用于检索令牌的用户名和密码)。

这里的最佳做法是什么?

【问题讨论】:

【参考方案1】:

我想我不能建议你如何用 Java 编写代码,但是我在用 php 创建应用程序时也遇到了 refresh_token 的一些问题,所以也许我的想法会对你有所帮助。

起初我在寻找永不过期的 refresh_token(就像在 Google API 中一样),所以我什至可以对其进行硬编码,并在我想创建一个新的 access_token 时使用它。无论如何,在 oAuth2 中真的很难做到。所以我在这里找到了关于这个问题的有趣观点:

Why do access tokens expire?

它向我展示了使用 refresh_token 的其他方式。我已经设置了我的 oAuth 服务,每次我使用 refresh_token 获取新的 access_token 时,它都会生成并返回一个新的 refresh_token。那部分对我帮助最大:

https://bshaffer.github.io/oauth2-server-php-docs/grant-types/refresh-token/

我们得到了类似的东西:

$server = new OAuth2\Server($storage, array(
    'always_issue_new_refresh_token' => true, // this part
    'refresh_token_lifetime'         => 2419200,
));

在这种情况下,我有一个长期存在的 refresh_token,我可以将它存储在某个地方,当我需要它时,我将使用它来获取新的 access_token,但响应也会为我提供一个新的 refresh_token,我可以再次存储它并在以后使用它用于获取新的 access_token。

因此,在您的情况下,我认为最好的方法是每次使用 refresh_token 请求 access_token 时继续生成 refresh_token。如果用户长时间不使用你的APP,我认为他应该重新授权自己。

【讨论】:

感谢您的回复!这或多或少是我最终实现的

以上是关于Android中的Oauth2刷新令牌更新的主要内容,如果未能解决你的问题,请参考以下文章

刷新的 OAuth2 令牌具有无效签名 (Azure AD OAuth2)

OAUTH2 刷新令牌

Google API OAuth2 刷新令牌突然被撤销

无法在跨客户端谷歌 oauth2.0 中交换访问令牌和刷新令牌的授权码

尝试使用spring oauth2中的刷新令牌获取新的访问令牌时出现无效的客户端错误

从Spring Security Oauth2中的Token Store检索访问和刷新令牌的方法