【问题标题】:Laravel Socialite token refreshingLaravel Socialite 令牌刷新
【发布时间】:2017-12-15 13:55:16
【问题描述】:

Socialite 获得的access_token(通过Socialite::driver(self::PROVIDER)->user() 的有效期有限。对于Google 来说是一个小时。

我可以通过将重定向调用更改为:

Socialite::driver(self::PROVIDER)->stateless()->with([
    'access_type' => 'offline',
])->redirect()

一个小时内,我可以通过调用读取基于access_token 的用户数据

// $token = read_stored_access_token()
\Socialite::driver(self::PROVIDER)->userFromToken($accessToken);

一小时后,当令牌失效时,Google API 开始返回 401 Unauthorized,Socialite 将其传播出去:

(1/1) ClientException
Client error: `GET https://www.googleapis.com/plus/v1/people/me?prettyPrint=false` resulted in a `401 Unauthorized` response:
{"error":{"errors":[{"domain":"global","reason":"authError","message":"Invalid Credentials","locationType":"header","loc (truncated...)

现在有了refresh_token,我应该可以轻松刷新access_token。但我在社交名流文档或源代码中找不到可以让我这样做的内容。

真的是使用 Google 的 API 库并手动完成此操作的唯一方法吗?它不会扼杀使用社交名流的整个想法吗?

注意:我试图避免再次致电redirect(),因为这可能会迫使用户每小时选择他的一个 Google 帐户,这很烦人。

谢谢!

【问题讨论】:

  • 还有一个后续问题:如果不手动实现自己的客户端就无法进一步使用refresh_token,那么提供访问权限有什么意义?

标签: php laravel laravel-socialite


【解决方案1】:

这是我通过离线访问从社交名流中保存用户的方式:

            $newUser                       = new User;
            $newUser->name                 = $user->name;
            $newUser->email                = $user->email;
            $newUser->google_id            = $user->id;
            $newUser->google_token         = $user->token;
            $newUser->token_expires_at     = Carbon::now()->addSeconds($user->expiresIn);
            $newUser->google_refresh_token = $user->refreshToken;
            $newUser->avatar               = $user->avatar;
            $newUser->avatar_original      = $user->avatar_original;
            $newUser->save();

这是我的令牌刷新解决方案。我是通过在我的用户模型中为令牌属性创建访问器来实现的:

    /**
     * Accessor for google token of the user
     * Need for token refreshing when it has expired
     *
     * @param $token
     *
     * @return string
     */
    public function getGoogleTokenAttribute( $token ) {
        //Checking if the token has expired
        if (Carbon::now()->gt(Carbon::parse($this->token_expires_at))) {
            $url  = "https://www.googleapis.com/oauth2/v4/token";
            $data = [
                "client_id"     => config('services.google.client_id'),
                "client_secret" => config('services.google.client_secret'),
                "refresh_token" => $this->google_refresh_token,
                "grant_type"    => 'refresh_token'
            ];

            $ch = curl_init($url);

            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            $result = curl_exec($ch);
            $err    = curl_error($ch);

            curl_close($ch);

            if ($err) {
                return $token;
            }
            $result = json_decode($result, true);

            $this->google_token     = isset($result['access_token']) ? $result['access_token'] : "need_to_refresh";
            $this->token_expires_at = isset($result['expires_in']) ? Carbon::now()->addSeconds($result['expires_in']) : Carbon::now();
            $this->save();

            return $this->google_token;

        }

        return $token;
    }

【讨论】:

    【解决方案2】:
    return Socialite::driver('google')
        ->scopes() 
        ->with(["access_type" => "offline", "prompt" => "consent select_account"])
        ->redirect();
    

    默认refresh_token仅在第一次授权时返回,通过添加“prompt”=>“consent select_account”我们强制每次都返回。

    【讨论】:

      猜你喜欢
      • 2019-03-22
      • 2019-09-17
      • 2019-05-15
      • 2015-05-19
      • 2019-03-23
      • 1970-01-01
      • 2019-11-17
      • 2020-09-14
      • 2019-07-04
      相关资源
      最近更新 更多