Laravel Socialite - 重定向前保存URL

时间:2017-06-19 02:43:14

标签: php redirect laravel-5.4 laravel-socialite

我正在使用Laravel 5.4Socialite,因此我的用户可以使用Facebook登录。

我的网站使用子域newyork.example.comparis.example.com example.com

回调登录的Facebook URL重定向必须为absolute,因此我设置http://example.com

登录/实

public function redirectToProvider()
    {

        $_SESSION['originalURL'] ="http://paris.example.com";

        return Socialite::driver('facebook')
            ->scopes(['rsvp_event', 'public_profile'])
            ->redirect();
    }

登录/实/回调

 public function handleProviderCallback(SocialAccountService $service)
    {
        $user = $service->createOrGetUser(Socialite::driver('facebook')->user());
        // $user->token;

        Auth::login($user, true);

        $originalURL = $_SESSION['originalURL'];

        return redirect()->to($originalURL);
    }

问题

当我在route登录/ facebook时,我可以使用paris.example.com

查看原始网址HTTP_POST

当我在路线login/facebook/callback时,HTTP_POSTexample.com,因为重定向的网址为example.com。我尝试将网址保存在session var中,但$_SESSION为空。

问题

如何在facebook登录回调重定向后获取原始网址。 ?因此,如果我使用paris.example.com启动登录过程,我会被重定向到example.com,然后我会将保存网址重定向到

sessions.php

'cookie' => 'laravel_session',

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Path
    |--------------------------------------------------------------------------
    |
    | The session cookie path determines the path for which the cookie will
    | be regarded as available. Typically, this will be the root path of
    | your application but you are free to change this when necessary.
    |
    */

    'path' => '/',

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Domain
    |--------------------------------------------------------------------------
    |
    | Here you may change the domain of the cookie used to identify a session
    | in your application. This will determine which domains the cookie is
    | available to in your application. A sensible default has been set.
    |
    */

    'domain' => env('SESSION_DOMAIN', '.localhost.com'),

    /*
    |--------------------------------------------------------------------------
    | HTTPS Only Cookies
    |--------------------------------------------------------------------------
    |
    | By setting this option to true, session cookies will only be sent back
    | to the server if the browser has a HTTPS connection. This will keep
    | the cookie from being sent to you if it can not be done securely.
    |
    */

    'secure' => env('SESSION_SECURE_COOKIE', false),

    /*
    |--------------------------------------------------------------------------
    | HTTP Access Only
    |--------------------------------------------------------------------------
    |
    | Setting this value to true will prevent JavaScript from accessing the
    | value of the cookie and the cookie will only be accessible through
    | the HTTP protocol. You are free to modify this option if needed.
    |
    */

    'http_only' => true,

3 个答案:

答案 0 :(得分:3)

我用这种方式,它的工作

public function socialConnectRedirect($type, Request $request)
{
    Session::put('redirect', $request->input('redirectTo'));
    if($type=='facebook'){
        return Socialite::driver($type)->scopes(['email', 'public_profile', 'user_birthday', 'user_location'])->redirect();
    }

    return Socialite::driver($type)->redirect();
}

在handleSocialCallback函数中,用户登录后

Auth::login($checkUser);
return redirect(Session::get('redirect'));
Session::forget('redirect');

答案 1 :(得分:1)

如果您无法在网站之间分享会话,则可以使用state OAuth参数来传递价值。

此代码已在自定义OAuth提供程序中进行了测试。以下是Facebook实现的样子(此特定代码未经测试)。

在更改state的工作方式时,请记住安全隐患。这是关于http://www.thread-safe.com/2014/05/the-correct-use-of-state-parameter-in.html的有趣写作。甚至还有关于如何将数据存储和签名到state参数https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-00的IETF草案(我的下面的实现使用JSON并且没有签名)。< / p>

<?php

namespace App\Socialite;

use Laravel\Socialite\Two\FacebookProvider;
use Laravel\Socialite\Two\User;

class CustomFacebookProvider extends FacebookProvider
{
    protected $statePreviousUrl = null;

    public function withPreviousUrl($url)
    {
        $this->statePreviousUrl = $url;

        return $this;
    }

    protected function getState()
    {
        // The state becomes a JSON object with both the XRSF protection token and the url
        return json_encode([
            'state' => parent::getState(),
            'url' => $this->statePreviousUrl,
        ]);
    }

    protected function hasInvalidState()
    {
        if ($this->isStateless()) {
            return false;
        }

        $storedState = $this->request->session()->pull('state');
        $requestState = $this->request->input('state');
        $requestStateData = json_decode($requestState, true);

        // If the JSON is valid we extract the url here
        if (!is_null($requestStateData) && array_key_exists('url', $requestStateData)) {
            // Don't forget, this value is unsafe. Do additional checks before redirecting to that url
            $this->statePreviousUrl = $requestStateData['url'];
        }

        // If you don't share your session between your instances you can play it "stateless" by always returning false here
        // Doing so you loose all XRSF protection ! (but this might be the only way if you don't share your cookies)
        // return false;

        // If the session is shared, we finish by checking the full state
        // We compare the full json objects, no need to extract the state parameter
        return ! (strlen($storedState) > 0 && $requestState === $storedState);
    }

    protected function mapUserToObject(array $user)
    {
        return (new User)->setRaw($user)->map([
            // Data here will vary from provider to provider. The Facebook one is a bit more complex
            'id'    => $user['id'],
            'email' => $user['email'],
            // We add the extracted URL here so it can be access from the controller
            'previous_url' => $this->statePreviousUrl,
        ]);
    }
}

注册自定义控制器:

<?php

namespace App\Socialite;

use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use Laravel\Socialite\Contracts\Factory;

class ServiceProvider extends BaseServiceProvider
{
    public function boot()
    {
        // @see https://medium.com/laravel-news/adding-auth-providers-to-laravel-socialite-ca0335929e42
        $socialite = $this->app->make(Factory::class);
        $socialite->extend(
            'custom-facebook',
            function ($app) use ($socialite) {
                $config = $app['config']['services.facebook'];
                return $socialite->buildProvider(CustomFacebookProvider::class, $config);
            }
        );
    }
}

用法:

<?php

namespace App\Http\Controllers;

use App\User;
use Laravel\Socialite\Contracts\Factory;

class FacebookLoginController extends Controller
{
    /**
     * @var Factory
     */
    protected $socialite;

    public function __construct(Factory $socialite)
    {
        $this->socialite = $socialite;
    }

    public function redirectToProvider()
    {
        return $this->socialite->driver('custom-facebook')->withPreviousUrl('https://paris.example.com/')->redirect();
    }

    public function handleProviderCallback()
    {
        $data = $this->socialite->driver('custom-facebook')->user();

        dd($data->previous_url);
    }
}

答案 2 :(得分:0)

关键是不要使用$_SESSION而是使用session(['city' => 'paris']);和session('city')来检索值。