Laravel Socialite - Save URL before redirection

匆匆过客 提交于 2021-01-28 03:18:58

问题


I'm using Laravel 5.4 and Socialite so my users can log in with Facebook.

My website works with subdomain newyork.example.com, paris.example.com example.com

The Facebook URL redirect for the callback login has to be absolute so I set http://example.com

login/facebook

public function redirectToProvider()
    {

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

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

login/facebook/callback

 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);
    }

Problems

When I am in the route login/facebook I can view the original URL paris.example.com with HTTP_POST

When I am in the route login/facebook/callback the HTTP_POST is example.com since the URL of the redirection is example.com. I tries to save the URL in a session var but $_SESSION is empty.

Questions

How I can do to get the original url after the facebook login callback redirection. ? So if I started the login process with paris.example.com I'm redirected to example.com and then I get the save url to be redirected

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,

回答1:


I use this way, it's work

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

In handleSocialCallback function, after user login

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



回答2:


If you can't share the session between the websites, here's a way to use the state OAuth parameter to carry the value along.

This code was tested in a custom OAuth provider. Here's how a Facebook implementation could look like (this specific code is untested).

There are security implications to keep in mind when changing the way the state works. Here's an interesting writing on that http://www.thread-safe.com/2014/05/the-correct-use-of-state-parameter-in.html There's even an IETF draft on how one would store and sign data into the state parameter https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-00 (My implentation below uses JSON and is not signed).

<?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,
        ]);
    }
}

Register the custom controller:

<?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);
            }
        );
    }
}

Usage:

<?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);
    }
}



回答3:


The key was not to use $_SESSION but session(['city' => 'paris']); and session('city') to retrieve the value.



来源:https://stackoverflow.com/questions/44621555/laravel-socialite-save-url-before-redirection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!