【问题标题】:Google Oauth Cross-client auth with javascript: Token has expired使用 javascript 的 Google Oauth 跨客户端身份验证:令牌已过期
【发布时间】:2015-01-06 07:00:15
【问题描述】:

我整天都在处理这个问题,但我就是不知道出了什么问题。

我有一个使用适用于 javascript 的 Google Api 客户端的应用程序,它可以正常工作。现在我想在服务器端做点什么,所以研究了一下,发现要走的路是在客户端使用令牌,在后端使用setAccessToken方法。

所以我尝试将我的令牌对象作为 JSON 发送(使用 JSON.stringify(gapi.auth.getToken()) ),一旦我尝试在需要身份验证的后端进行 API 调用,就会收到以下错误:

OAuth 2.0 访问令牌已过期,刷新令牌不可用。自动批准的响应不会返回刷新令牌。

所以,有点困惑,我尝试在谷歌的端点上使用 curl 来验证令牌,它返回以下内容

{
    "issued_to": "client_id",
    "audience": "client_id",
    "user_id": "user_id",
    "scope": "https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me",
    "expires_in": 1465,
    "email": "user_email",
    "verified_email": true,
    "access_type": "online"
}

所以我知道令牌很好且有效。我的代码设置方式如下(编辑为:

<?php
// The token JSON is not inline, it comes from another source directly from the client side, but this is how it looks
$token_json = '{"state":"","access_token":"TOTALLY_VALID_ACCESS_TOKEN","token_type":"Bearer","expires_in":"3600","scope":"https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me","client_id":"CLIENT_ID","g_user_cookie_policy":"single_host_origin","cookie_policy":"single_host_origin","response_type":"token","issued_at":"1415583001","expires_at":"1415586601","g-oauth-window":{},"status":{"google_logged_in":false,"signed_in":true,"method":"PROMPT"}}';

$OAUTH2_CLIENT_ID = 'CLIENT_ID';
$OAUTH2_CLIENT_SECRET = 'CLIENT_SECRET';

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setAccessToken($token_json);

$youtube = new Google_Service_YouTube($client);

try{

    /* Random code goes here */

    // Auth Exception here.
    $insertRequest = $youtube->videos->insert("status,snippet", $video);

} catch (Google_Exception $e) {
    var_dump($e->getMessage());
}   

我需要设置离线访问吗?我要求登录过程必须在 javascript 中,所以没有机会从后端重新创建登录流程。

我有什么遗漏的吗?

【问题讨论】:

    标签: javascript php oauth google-api-php-client


    【解决方案1】:

    好吧,如果其他人偶然发现:

    显然,直接共享令牌不是可行的方法,因为不同的 API 包装器处理令牌的方式不同。您要做的就是将一次性代码传递给 PHP 并使用以下内容获取访问令牌

        $client = new Google_Client();
        $client->setClientId($OAUTH2_CLIENT_ID);
        $client->setClientSecret($OAUTH2_CLIENT_SECRET);
    
        // Couldn't find this anywhere in the docs, but it's required. If you don't pass this, you will get an Origin Mismatch error.
        $client->setRedirectUri('postmessage'); 
    
        // Get this from javascript
        $client->authenticate($ONE_TIME_CODE);
    
        // Optionally, you might want to retrieve the token and save it somewhere else e.g. the session, as the code is only good for a single use.         
        $_SESSION['token'] = $client->getAccessToken(); 
    

    此外,除了 JS 令牌之外,您还需要从 JS 中指定您需要此一次性代码,我在其他任何地方也找不到该代码。

    gapi.auth.authorize 的示例设置

    {
            client_id: CLIENT_ID
            scope: APP_SCOPES
            cookie_policy: 'single_host_origin'
            response_type: 'code token'
            immediate: true
    }
    

    【讨论】:

    • 使用“postmessage”作为重定向 URL 是我的关键信息。
    【解决方案2】:

    非常感谢,小胡子。我也花了一整天的时间来解决这个问题。但是,我发现什么是一次性代码以及如何获取它并不那么明显,所以我决定在这里提供我的代码,以防其他人遇到同样的问题:

    <html>
        <head>
            <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
            <script src="https://apis.google.com/js/platform.js?onload=onGoogleAPILoad" async defer></script>
            <script>
                $(document).ready(function() {
                    var auth2;
    
                    window.onGoogleAPILoad = function() {
                        gapi.load('auth2', function() {
                            auth2 = gapi.auth2.init({ client_id: 'CLIENT_ID', scope: 'profile' });
                        });
                    };
    
                    $('button').on('click', function() {
                        auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(function(response) {
                            $.ajax({
                                method: 'POST',
                                url: '/auth/signin',
                                success: onAuthSuccess = function(response) {
                                    // check response from your server and reload page if succeed
                                },
                                data: { code: response.code }
                            });
                        });
                    });
                });
            </script>
        </head>
        <body>
            <button>Sign In</button>
        </body>
    </html>
    

    后端的代码几乎相同:

    $client = new Google_Client();
    $client->setClientId('CLIENT_ID');
    $client->setClientSecret('CLIENT_SECRET');
    $client->setRedirectUri('postmessage'); 
    
    $client->authenticate($code); // here is one-time code
    
    $plus = new Google_Service_Plus($client);
    $user = $plus->people->get('me');
    // $user is in array, containing now id, name, etc.
    

    这是关于该主题的article

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 2014-06-26
      • 2015-11-12
      • 2020-06-09
      • 2015-01-12
      • 1970-01-01
      • 2021-07-23
      • 2014-12-24
      • 2013-08-19
      相关资源
      最近更新 更多