简体   繁体   English

Laravel Socialite 令牌刷新

[英]Laravel Socialite token refreshing

The access_token acquired by Socialite (via Socialite::driver(self::PROVIDER)->user() has a limited time validity. For Google it's an hour. Socialite(通过Socialite::driver(self::PROVIDER)->user()获取的access_token是有时间限制的,Google是一个小时。

I'm able to get refresh_token by changing the redirect call to:我可以通过将重定向调用更改为以下方式来获取refresh_token

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

For an hour I'm able to read user data based on access_token by calling一个小时后,我可以通过调用来读取基于access_token的用户数据

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

After an hour, when the token gets invalid, the Google API starts returning 401 Unauthorized and Socialite propagates this out:一个小时后,当令牌无效时,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...)

Now with the refresh_token , I should be able to easily refresh the access_token .现在有了refresh_token ,我应该能够轻松地刷新access_token But I cannot find a mention in Socialite docs or source code which would allow me to do that.但是我在 Socialite 文档或源代码中找不到允许我这样做的提及。

Is really the only way how to accomplish this use Google's API library and do this manually?真的是使用 Google 的 API 库并手动执行此操作的唯一方法吗? Doesn't it kill the whole idea of using Socialite?它不会扼杀使用 Socialite 的整个想法吗?

Note: I'm trying to avoid to call redirect() again as it might force user to pick one of his Google accounts every hour which is annoying.注意:我试图避免再次调用redirect() ,因为它可能会迫使用户每小时选择一个他的 Google 帐户,这很烦人。

Thanks!谢谢!

Here is the way I saving user from Socialite with offline access:这是我通过离线访问从 Socialite 中保存用户的方式:

            $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();

And here is my solution for token refreshing.这是我的令牌刷新解决方案。 I made it via creating accessor for token attribute in my User model:我通过在我的用户模型中为令牌属性创建访问器来实现它:

    /**
     * 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;
    }
return Socialite::driver('google')
    ->scopes() 
    ->with(["access_type" => "offline", "prompt" => "consent select_account"])
    ->redirect();

By default refresh_token is returned only on first authorization, by adding "prompt" => "consent select_account" we force it to be returned every time.默认情况下,refresh_token 仅在第一次授权时返回,通过添加“prompt”=>“consent select_account”,我们强制每次都返回它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM