Laravel社交名媛:InvalidStateException


68

我正在使用Laravel Socialite在网站上添加Facebook连接按钮。有时,我在回调中遇到此错误:

exception 'Laravel\Socialite\Two\InvalidStateException' 
in /example/vendor/laravel/socialite/src/Two/AbstractProvider.php:161

我不知道这是什么意思,也没有找到有关此错误的任何信息。真正的问题是它似乎是一个随机异常(不了解为什么会发生)。那么这个错误是什么意思以及如何避免呢?

看来这与Laravel 5在AbstractProvider.php中获取InvalidStateException不同,因为在我看来,这是随机的。


我认为这可能是问题所在,stackoverflow.com
a/29975589/1430587


确实很近,但是由于随机性,我认为这不是一个相同的问题
rap-2-h

1
当我从不同的URL路径访问我的应用程序时遇到了这个问题,例如,如果我尝试从www.mysite.com/登录,它将起作用,但是如果我通过访问http:\\ mysite.com进行访问,则会出现该错误。
克里斯·汤森

1
问题是它是真正随机的还是只是随机出现的(人类很难识别真正的随机现象)。当引发此异常时,我将开始记录所有内容,以查看是否出现模式。鉴于其他人(@ChrisTownsend和我本人,在上面引用的答案中)已将其识别为可能与会话cookie问题相关,因此我将从此处开始。
Kryten 2015年

Answers:


97

昨晚我遇到了这个问题,并使用以下解决方案解决了这个问题。

有关我的问题的更多信息,我已经

第182行AbstractProvider.php中的InvalidStateException

在该功能中,handleProviderCallback()当它从Facebook登录名重新定向回去时。这似乎与您的问题相同。

此外,我发现在不打开的情况下出现问题www。当我打开网站时www.mysite.com-没问题。起初,我认为我的问题是随机的,直到我得到Chris Townsend对问题的答复的线索为止-非常感谢。

解决方案

  1. 转到您的www根目录,检查laravel文件 config/session.php
  2. 检查会话会话Cookie域默认配置是'domain' => null,我对进行了更改'domain' => 'mysite.com'
  3. 之后'php artisan cache:clear''composer dump-autoload',我都可以从www.mysite.com和登录mysite.com

完成这些修改后,在测试时,请务必从浏览器中删除Cookie。旧的Cookie仍然会产生问题。


1
正确,但适用于使用localhost和Chrome的用户。请记住,Chrome现在确实为localhost设置了cookie,因此仍然存在问题,以解决在主机文件中添加有效的域名(其中带有点号的域名),然后相应地更改laravel配置文件的问题。
ggat 2015年

2
如果是本地主机,我应该为域写什么?

1
需要在config / session.php中同时更改“ domain”和“ cookie”值。否则,用户将获得意外的登录问题。请参阅stackoverflow.com/questions/33260856/...
ruwan800

1
先生,您是救生员!谢谢
lomse

2
我只是将www重定向到中的非www .htaccess。我使用了这篇文章该文章还将HTTP重定向到HTTPS。
totymedli

56

解决 :

Socialite::driver('google')->stateless()->user()

执行此操作时,重定向后用户未登录。我使用auth()-> login($ user); 等等...
cmac

3
确保也添加stateless()到重定向行,否则重定向后登录可能会遇到麻烦。 Socialite::driver('google')->stateless()->redirect()
HelloSpeakman

为我工作,以防万一我必须从一个子域登录并重定向回另一个子域。
拉胡尔·沙尔玛

我应该在哪里插入Socialite::driver('google')->stateless()->user()?在什么文件中?谢谢。
Eem Jee

1
它有什么作用,为什么您需要它?
挖出

17

tl; dr

如果需要读取state第三方服务返回的给定参数,则可以将Socialite设置为避免使用以下stateless方法进行此检查:

   Socialite::driver($provider)->stateless();

我认为Socialite已经准备避免该问题。

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L77

 /**
 * Indicates if the session state should be utilized.
 *
 * @var bool
 */
protected $stateless = false;

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L374

/**
 * Indicates that the provider should operate as stateless.
 *
 * @return $this
 */
public function stateless()
{
    $this->stateless = true;
    return $this;
}

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L222

/**
 * Determine if the current request / session has a mismatching "state".
 *
 * @return bool
 */
protected function hasInvalidState()
{
    if ($this->isStateless()) {
        return false; // <--------
    }
    $state = $this->request->getSession()->pull('state');
    return ! (strlen($state) > 0 && $this->request->input('state') === $state);
}

例如,state对于通过Google传递数据非常有用:

参数:state(任何字符串)
在收到响应后,提供可能对您的应用程序有用的任何状态。Google Authorization Server会往返传递此参数,因此您的应用程序会收到与发送的相同值。可能的用途包括将用户重定向到您站点中的正确资源,以及跨站点请求伪造缓解措施。

参考:https : //developers.google.com/identity/protocols/OAuth2UserAgent#overview


这对我有用Socialite :: driver($ provider)-> stateless();
哈里·波什

正如文档所说,这可能很危险Possible uses include [...] cross-site-request-forgery mitigations
蒂姆(Tim)


@HarryBosh您插入了文件的哪一部分?在什么文件中?谢谢。
Eem Jee

7

现有答案中没有两个主要的“陷阱”。

  1. 有时InvalidStateException是红色鲱鱼,真正的根本原因是其他一些错误。我花了大约12个小时才意识到我还没有$fillable在模型的数组中添加新字段。
  2. 除非您禁用会话状态验证(如此处的其他答案似乎要您执行,但并非每个人都想这样做),否则$provider->user() 每个请求只能被调用一次,因为该函数内部会调用hasInvalidState(),然后从中删除“ state”项会议。我花了几个小时才意识到我碰巧要$provider->user()多次调用,而我本应该只调用一次并将结果保存到变量中。

4

通过移动网络使用Facebook应用而非浏览器中的Facebook登录时,我仅遇到此错误。Facebook应用程序在登录后使用的是Facebook浏览器,而不是您当前的浏览器,因此不会意识到以前的状态。

try {
    $socialite = Socialite::driver($provider)->user();
} catch (InvalidStateException $e) {
    $socialite = Socialite::driver($provider)->stateless()->user();
}

3

还要检查对您的storage/framework/sessions文件夹的访问权限。

就我而言,由于该文件夹在新的Laravel项目中为空,因此在最初提交到GIT存储库期间已被删除。之后,我在生产服务器上手动创建了它,但是显然具有错误的访问权限,因此它对于会话驱动程序是不可写的(当设置为时'file')。


3

仅当我在移动设备上打开网站并在手机上通过Facebook应用程序打开对话框时,我才会遇到同样的情况。

我认为:发生这种情况是因为打开Facebook应用程序以从Facebook API获得响应使我们丢失了一些cookie。它变得无状态了。然后,我只使用socialite已经避免stateless请求的选项。

$user = Socialite::driver($provider)->stateless()->user();

对我有用。希望对你有帮助


2

在我的情况下,这是由类中$fillable数组中的参数丢失引起的User。当我添加所有缺少的参数时,它开始正常工作。


1

我遇到了同样的问题,我只是清除了缓存以解决此问题。我只是运行了此命令,然后再次开始了该过程。

php artisan cache:clear

我希望这个答案可以对某人有所帮助。


1

我有一个类似的问题,我有

InvalidStateException in AbstractProvider.php line 182

在功能 handleProviderCallback() 从Facebook登录名重新指向时。这似乎与您的问题相同。

此外,我发现在没有打开网站时出现问题 www。当我打开网站时 www.mysite.com -没问题。起初,我认为我的问题是随机的,直到我得到克里斯·汤森德对问题的答复的线索为止。

解决方案

转到您的www根目录,检查laravel文件 config/session.php。检查会话Session Cookie Domain。默认配置是 

'domain' => null,

我改变了 

'domain' => 'mysite.com' 

php artisan cache:clear 和 之后 composer dump-autoload,我都可以从www.mysite.com和mysite.com顺利登录

完成这些修改后,在测试时,请务必从浏览器中删除Cookie。旧的Cookie仍然会产生问题。


如果为此问题提供的答案不能解决您的问题,请提出一个新问题。:-)
Brian Peacock

1

得到了解决方案-2018年11月更新

public function redirectToGoogle(Request $request)
{
    /**
     * @var GoogleProvider $googleDriver
     */
    $googleDriver = Socialite::driver("google");
    return $googleDriver->redirect();
}

public function fromGoogle(Request $request)
{
    try {
/*
Solution Starts ----
*/
        if (empty($_GET)) {
            $t = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
            parse_str($t, $output);
            foreach ($output as $key => $value) {
                $request->query->set($key, $value);
            }
        }
/*
Solution Ends ----
*/
        /**
         * @var GoogleProvider $googleDriver
         */
        $googleDriver = Socialite::driver("google");
        print_r($googleDriver->user());
    } catch (\Exception $e) {
        print_r($e->getMessage());
    }

1

Laravel 6.16.0
PHP 7.4.2

我碰到了这个确切的问题。原来我最近更改same_sitestrict,社交名流引发了InvalidStateException异常。然后我将其更改回了null,一切正常。

/*
    |--------------------------------------------------------------------------
    | Same-Site Cookies
    |--------------------------------------------------------------------------
    |
    | This option determines how your cookies behave when cross-site requests
    | take place, and can be used to mitigate CSRF attacks. By default, we
    | do not enable this as other CSRF protection services are in place.
    |
    | Supported: "lax", "strict"
    |
    */

    'same_site' => null,

1

2020/04

如果您在2020年2月左右出现此问题,则很有可能与2020年2月初发布的Google Chrome 80+版本有关。我不会假装我完全理解该问题,但简而言之,如果未指定SameSite属性,则默认情况下,Google Chrome现在默认将Cookie视为SameSite = Lax。

如果您的应用依赖于有效的跨站点Cookie,则需要在Cookie中添加“ SameSite = None; Secure”。在Laravel 5.5+中,您可以通过更改会话配置来实现:

config / session.php

'secure' => env('SESSION_SECURE_COOKIE', true), // or set it to true in your .env file

...

'same_site' => "none",

Laravel的早期版本显然不支持“ none”值。但是现在,如果这会产生奇怪的错误检查/vendor/symfony/http-foundation/Cookie.php并确保有一个SAMESITE_NONE常数。如果不存在,则可能需要升级Laravel版本。

进一步阅读:


0

如果您仍然需要帮助,可以使用我的代码,它对我有用。您只需要创建两个路由并更新users表。不要忘记使密码可以为空,因为您不会从facebook用户那里得到一个密码。我的控制器中的代码:

public function redirectToProvider()
{
    return Socialize::with('facebook')->redirect();
}

public function handleProviderCallback(User $user)
{
    $money = Socialize::with('facebook')->user();

    if(User::where('email', '=', $money->email)->first()){
    $checkUser = User::where('email', '=', $money->email)->first();
    Auth::login($checkUser);
    return redirect('home');
     } 

    $user->facebook_id = $money->getId();
    $user->name = $money->getName();
    $user->email = $money->getEmail();
    $user->avatar = $money->getAvatar();
    $user->save();

    Auth::login($user);
    return redirect('home');

}

0

我修复了这个问题,只是将SESSION DRIVER禁用为数据库。


0

这为我解决了
$request->session()->put('state',Str::random(40)); $user = Socialite::driver('github')->stateless()->user();


0

在控制器上的callback()方法

$ user = $ service-> createOrGetUser(Socialite :: driver('facebook')-> user());

$user = $service->createOrGetUser(Socialite::driver('facebook')->stateless()->user());


0

在我的场景中,我有两个Laravel应用程序在localhost上运行,一个实现护照,并且利用社交名流对护照应用程序进行身份验证。我忘了设置APP_NAMEin .env,所以每个应用程序都在写相同的lavarel_sessioncookie,因此社交名流应用程序无法从会话中获取状态值,因为另一个应用程序踩了cookie。

如果您的应用程序在同一域上运行并且正在使用您自己的提供程序,请确保APP_NAME.env设置应用程序时将值设置为in 。


0

Laravel:7.10.3

PHP:7.3.15

我也有这个问题。提出的解决方案以某种方式并没有帮助我解决问题。

在花了很多时间试图修复我的代码之后,我认为这也可能与我的php-fpm-> nginx设置有关。

更改我的nginx配置后,现在可以通过Facebook登录。

错误的配置:

location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   unix:/var/run/php-fpm/www.sock;
}

location / {
   try_files $uri $uri/ /index.php;
}

正确配置

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm/www.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

0

我在这两天堆放着 'driver' => env('SESSION_DRIVER', 'file')'driver' => env('SESSION_DRIVER', 'cookie')为我工作


0

对我来说,解决方案是设置APP_URLhttp://localhost:8000而不是http://127.0.0.1:8000(假定您在8000端口上运行服务器)。

然后,清理配置并缓存:

  • php artisan config:clear
  • php artisan cache:clear

清除Cookie(或以隐身模式运行)

由于localhost默认情况下Facebook允许重定向,因此您无需在fb应用程序中将网址列入白名单。


0

2020年10月

对我来说,

…\vendor\laravel\socialite\src\Two\AbstractProvider.php209

所以我从

$user = Socialite::driver('facebook')->user();

$user = Socialite::driver('facebook')->stateless()->user();

我不必运行任何缓存清除操作,尽管确实删除了cookie,但是我不确定您是否必须这样做。




-5

我想分享给我我的解决方案。我去我的AbstractProvider.php文件并解决问题

public function user()
{
    if ($this->hasInvalidState()) {
        throw new InvalidStateException;
    }

    // ...
}

我停止throw newInvalidStateException并像这样调用重定向函数:

public function user()
{
    if ($this->hasInvalidState()) {
        $this->redirect();
        // throw new InvalidStateException;
    }

    // ...
}

这只是在无限循环中启动身份验证,对吗?redirect()是过程的第一部分,而user()第二部分是...
Kaktus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.