在Android上集成Google登录时,ID令牌过期后如何刷新?

1yjd4xko  于 5个月前  发布在  Android
关注(0)|答案(2)|浏览(79)

我已经按照https://developers.google.com/上的指南操作,在用户登录后,我可以获得登录用户的Google ID令牌。但我注意到该令牌将在1小时后过期。我找不到任何官方参考,告诉我如何处理过期的Google ID令牌,所以我只能要求用户再次单击Google登录按钮。
如何在旧的Google ID令牌过期后刷新有效的Google ID令牌,而不打扰用户一次又一次地手动登录?

j8ag8udp

j8ag8udp1#

是的,Google ID令牌的有效期为一小时,并且会过期,您只需在应用中使用silentSignIn即可获得新令牌,无需任何用户交互。如果您现有的令牌尚未过期,您将获得(缓存)版本(返回的OptionalPendingResult将有isDone() == true);如果它已经过期了,你会得到一个刷新的(但它会花更长的时间,因此OptionalPendingResult isDone()将是false)。
下面是示例代码(UI线程,请参阅下面关于工作线程的注解):

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.server_client_id))

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build();
...

    OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
    if (opr.isDone()) {
        // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
        // and the GoogleSignInResult will be available instantly.
        Log.d(TAG, "Got cached sign-in");
        GoogleSignInResult result = opr.get();
        handleSignInResult(result);  // result.getSignInAccount().getIdToken(), etc.
    } else {
        // If the user has not previously signed in on this device or the sign-in has expired,
        // this asynchronous branch will attempt to sign in the user silently.  Cross-device
        // single sign-on will occur in this branch.
        opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
            @Override
            public void onResult(GoogleSignInResult googleSignInResult) {
                handleSignInResult(googleSignInResult);  // result.getSignInAccount().getIdToken(), etc.
            }
        });
    }

字符串
记住你是在UI线程还是工作线程上调用silentSignIn。如果你在工作线程上调用它,看看这篇文章用blockingConnect() + await()简化了代码很多:静默登录用GoogleApiClient检索令牌

2nbm6dog

2nbm6dog2#

我在Android应用程序中尝试使用Google Photos Java API沿着Google Sign In时遇到了这个问题。Here is the problem I was facing。我基本上通过定期获取PhotosLibraryClient的新示例来解决这个问题,该示例本身在此过程中获取新的GoogleAccountCredential。但我确实必须小心在创建新的PhotosLibraryClient之前正确拆除现有的PhotosLibraryClient

var lastGooglePhotosClientRefreshTimestamp = 0L

    fun createGooglePhotosClient(token: String): PhotosLibraryClient? {
        return try {
            App.googlePhotosClient?.let { client ->
                if (!client.isShutdown) {
                    client.shutdownNow()
                    client.awaitTermination(30, TimeUnit.SECONDS)
                    client.close()
                }
            }
            val settings = PhotosLibrarySettings.newBuilder().setCredentialsProvider(
                FixedCredentialsProvider.create(getUserCredentials(token))).build()
            val photosLibraryClient = PhotosLibraryClient.initialize(settings)
            if (photosLibraryClient == null) {
                logMessage(TAG, "Google Photos library client could not be fetched.")
            } else {
                App.googlePhotosClient = photosLibraryClient
                lastGooglePhotosClientRefreshTimestamp = System.currentTimeMillis()
            }
            return photosLibraryClient
        } catch (throwable: Throwable) {
            logMessage(TAG, throwable.stackTraceToString())
            null
        }
    }

    private fun getUserCredentials(token: String): UserCredentials {
        val accessToken = AccessToken(token, null)
        return UserCredentials.newBuilder()
            .setClientId(App.appContext.getString(R.string.google_client_id))
            .setClientSecret(App.appContext.getString(R.string.google_client_secret))
            .setAccessToken(accessToken)
            .build()
    }

    // Call this method at or near the time of credential expiration 
    // to avoid an UnauthenticatedException. The server will only
    // grant you a new credential in such a circumstance
    // (otherwise it will return the same credential).
    suspend fun refreshGooglePhotosClient() {
        withContext(Dispatchers.Default) {
            if (App.googleSignInAccount == null) return@withContext
            val credential = getGoogleAccountCredential(App.googleSignInAccount!!, true, false)
            try {
                val token = credential.token
                createGooglePhotosClient(token)
            } catch (throwable: Throwable) {
                logMessage(TAG, "Error while calling refreshGooglePhotosClient(): ${throwable.stackTraceToString()}")
            }
        }
    }

// Fetch a GoogleSignInClient with all the required Scopes requested.
fun getGoogleSignInClient(activity: Activity, needsPhotosScope: Boolean, needsDriveScope: Boolean): GoogleSignInClient {
    val signInOptions = GoogleSignInOptions
        .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestServerAuthCode(App.appContext.getString(R.string.google_client_id), true)
        .requestEmail()
    val scopes = getRequiredGoogleServiceScopes(needsPhotosScope, needsDriveScope)
    when (scopes.size) {
        0 -> throw RuntimeException("Attempting to use Google Sign-In without requesting any Scopes.")
        1 -> signInOptions.requestScopes(scopes[0])
        2 -> signInOptions.requestScopes(scopes[0], scopes[1])
    }
    return GoogleSignIn.getClient(activity, signInOptions.build())
}

fun getGoogleAccountCredential(googleSignInAccount: GoogleSignInAccount, needsPhotosScope: Boolean,
                               needsDriveScope: Boolean): GoogleAccountCredential {

    // Create list of Scopes in String form.
    val scopeStringList = getRequiredGoogleServiceScopes(needsPhotosScope, needsDriveScope).map { it.scopeUri }

    val credential = GoogleAccountCredential.usingOAuth2(App.appContext, scopeStringList)
    credential.selectedAccount = googleSignInAccount.account
    return credential
}

// Fetch a List of Scopes that match the requirements based on the user's current search criteria.
fun getRequiredGoogleServiceScopes(needsPhotosScope: Boolean, needsDriveScope: Boolean): List<Scope> {
    val scopes = mutableListOf<Scope>()
    if (needsPhotosScope) scopes.add(Scope(googlePhotosScope))
    if (needsDriveScope) scopes.add(Scope(DriveScopes.DRIVE))
    return scopes
}

字符串

相关问题