Laravel przekierowuje z powrotem do pierwotnego miejsca docelowego po zalogowaniu

189

Wydaje się to dość prostym przepływem i Laravelma tak wiele fajnych rozwiązań dla podstawowych rzeczy, czuję, że coś mi brakuje.

Użytkownik klika łącze wymagające uwierzytelnienia. Filtr uwierzytelniania Laravela uruchamia się i kieruje je na stronę logowania. Użytkownik loguje się, a następnie przechodzi do oryginalnej strony, do której próbowali dotrzeć, zanim uruchomił się filtr „auth”.

Czy istnieje dobry sposób, aby dowiedzieć się, do której strony starali się dotrzeć? Ponieważ Laravel jest tym, który przechwytuje żądanie, nie wiedziałem, czy to gdzieś śledzi dla łatwego routingu po zalogowaniu się użytkownika.

Jeśli nie, byłbym ciekawy, jak niektórzy z was wdrożyli to ręcznie.

JOV
źródło

Odpowiedzi:

234

Dla Laravel 5.3 i nowszych

Sprawdź odpowiedź Scotta poniżej.

Dla Laravel 5 do 5.2

Po prostu,

W przypadku oprogramowania pośredniego uwierzytelniania:

// redirect the user to "/login"
// and stores the url being accessed on session
if (Auth::guest()) {
    return redirect()->guest('login');
}
return $next($request);

Podczas akcji logowania:

// redirect the user back to the intended page
// or defaultpage if there isn't one
if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return redirect()->intended('defaultpage');
}

Dla Laravela 4 (stara odpowiedź)

W chwili udzielania odpowiedzi nie było oficjalnego wsparcia ze strony samych ram. W dzisiejszych czasach możesz używaćmetoda wskazana przez bgdrl poniżejta metoda: (Próbowałem zaktualizować jego odpowiedź, ale wygląda na to, że nie zaakceptuje)

Na filtrze uwierzytelniania:

// redirect the user to "/login"
// and stores the url being accessed on session
Route::filter('auth', function() {
    if (Auth::guest()) {
        return Redirect::guest('login');
    }
});

Podczas akcji logowania:

// redirect the user back to the intended page
// or defaultpage if there isn't one
if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return Redirect::intended('defaultpage');
}

Dla Laravel 3 (nawet starsza odpowiedź)

Możesz to zaimplementować w następujący sposób:

Route::filter('auth', function() {
    // If there's no user authenticated session
    if (Auth::guest()) {
        // Stores current url on session and redirect to login page
        Session::put('redirect', URL::full());
        return Redirect::to('/login');
    }
    if ($redirect = Session::get('redirect')) {
        Session::forget('redirect');
        return Redirect::to($redirect);
    }
});
// on controller
public function get_login()
{
    $this->layout->nest('content', 'auth.login'); 
}

public function post_login()
{
    $credentials = [
        'username' => Input::get('email'),
        'password' => Input::get('password')
    ];

    if (Auth::attempt($credentials)) {
        return Redirect::to('logged_in_homepage_here');
    }

    return Redirect::to('login')->with_input();
}

Przechowywanie przekierowania na Sesji ma tę zaletę, że trwa, nawet jeśli użytkownik nie wpisuje swoich danych logowania lub nie ma konta i musi się zarejestrować.

Pozwala to również na cokolwiek innego niż Auth, aby ustawić przekierowanie na sesję i będzie działać magicznie.

vFragosop
źródło
Czy nie ma większego sensu flashowanie sesji zamiast wstawiania i zapominania? Twoja czynność logowania po prostu zwróci przekierowanie do wartości w sesji, jeśli istnieje, lub domyślnej strony w przeciwnym razie.
bilalq 13.03.13
2
Zredagowałem odpowiedź, aby wyjaśnić, dlaczego jest to lepsze niż flash.
vFragosop
To ma sens. Lepsze niż za każdym razem ponowne flashowanie.
bilalq 13.03.2013
1
Po przejściu funkcji Auth :: próba () możesz po prostu przekierować użytkownika na domyślną stronę (zwykle do jego strony domowej). Przekierowanie ponownie przejdzie przez ten filtr i przekieruje go do pierwotnego żądanego adresu URL, jeśli taki istnieje. W przeciwnym razie po prostu będzie nadal renderować swój dom. Podam przykład akcji logowania.
vFragosop
1
w 5.1 jest w oprogramowaniu pośrednim RedirectIfAuthenticated.php: if ($ this-> auth-> check ()) {return redirect ('/ privatepage'); }
Dave Driesmans
73

Laravel> = 5,3

Zmiany Auth w 5.3 sprawiają, że implementacja tego jest nieco łatwiejsza i nieco inna niż 5.2, ponieważ Auth Middleware zostało przeniesione do kontenera usług.

Zmodyfikuj nowy readresator uwierzytelniania oprogramowania pośredniego

/app/Http/Middleware/RedirectIfAuthenticated.php

Zmień nieco funkcję uchwytu, aby wyglądało to tak:

public function handle($request, Closure $next, $guard = null)
{
    if (Auth::guard($guard)->check()) {
        return redirect()->intended('/home');
    }

    return $next($request);
}

Wyjaśnienie TL; DR

Jedyną różnicą jest czwarta linia; domyślnie wygląda to tak:

return redirect("/home");

Ponieważ Laravel> = 5.3 automatycznie zapisuje ostatnią „zamierzoną” trasę podczas sprawdzania funkcji Auth Guard, zmienia się na:

return redirect()->intended('/home');

To mówi Laravelowi, aby przekierował na ostatnią zamierzoną stronę przed zalogowaniem, w przeciwnym razie przejdź do „/ home” lub tam, gdzie chcesz je domyślnie wysłać.

Mam nadzieję, że pomoże to komuś innemu - niewiele jest różnic na temat różnic między 5.2 a 5.3, aw szczególności w tej dziedzinie jest ich sporo.

Scott Byers
źródło
2
dla Laravela 6.4 to już nie działa ... jakiś pomysł, proszę?
alex toader
Chciałbym return redirect()->intended(RouteServiceProvider::HOME);trzymać twoją domową ścieżkę w jednym miejscu.
Mateusz
26

Znalazłem te dwie świetne metody, które mogą być dla ciebie niezwykle pomocne.

Redirect::guest();
Redirect::intended();

Możesz zastosować ten filtr do tras wymagających uwierzytelnienia.

Route::filter('auth', function()
{
    if (Auth::guest()) {
           return Redirect::guest('login');
    }
});

Ta metoda w zasadzie polega na przechowywaniu strony, którą próbujesz odwiedzić, i przekierowuje Cię na stronę logowania .

Gdy użytkownik zostanie uwierzytelniony, możesz zadzwonić

return Redirect::intended();

i przekierowuje Cię na stronę, którą próbujesz otworzyć na początku.

To świetny sposób na zrobienie tego, chociaż zwykle używam poniższej metody.

Redirect::back()

Możesz sprawdzić ten niesamowity blog.

giannis christofakis
źródło
Jest to znacznie lepsze niż powyższe rozwiązania. Powyższe rozwiązania wymagają możliwości zamknięcia funkcji logowania, czego nie mogłem zrobić z 4.1. Ale było to o wiele prostsze i działało tak, jak jest.
user2662680,
20

Możesz użyć funkcji Przekierowanie :: zamierzone . Przekieruje użytkownika do adresu URL, do którego próbował uzyskać dostęp, zanim zostanie złapany przez filtr uwierzytelniania. W przypadku tej metody można podać rezerwowy identyfikator URI, jeżeli zamierzone przeznaczenie nie jest dostępne.

W postu zaloguj / zarejestruj się:

return Redirect::intended('defaultpageafterlogin');
dabuno
źródło
11

Używam tego od jakiegoś czasu w kodzie wyboru języka. O ile wystarczy cofnąć tylko o jedną stronę, działa dobrze:

return Redirect::to(URL::previous());

To nie jest najskuteczniejsze rozwiązanie, ale jest super łatwe i może pomóc rozwiązać kilka zagadek. :)

Federico Stango
źródło
5
Tak poprzednie () działa dobrze. Ale jeśli twój pierwszy wysiłek logowania się nie powiedzie (więc strona „logowanie nieudane” stanie się twoją poprzednią stroną), a drugi wysiłek logowania się powiedzie, zostaniesz ponownie przekierowany na stronę logowania (co może przekierować cię na stronę główną).
Shriganesh Shintre
11

Zmień konstruktora LoginControllers na:

public function __construct()
    {
        session(['url.intended' => url()->previous()]);
        $this->redirectTo = session()->get('url.intended');

        $this->middleware('guest')->except('logout');
    }

Nastąpi przekierowanie z powrotem do strony PRZED stroną logowania (2 strony wstecz).

MevlütÖzdemir
źródło
Jedyny, który dla mnie działa. To musi znaczyć, że mam gdzieś inne przekierowanie, ale kto wie gdzie.
Arthur Tarasov
8
return Redirect::intended('/');

spowoduje to przekierowanie do domyślnej strony twojego projektu, tj. strony początkowej.

Parag Bhingre
źródło
6

W przypadku laravel 5. * wypróbuj te.

return redirect()->intended('/');

lub

return Redirect::intended('/');
Nuruzzaman Milon
źródło
5

Laravel 3

Lekko poprawiłem twój kod (Vinícius Fragoso Pinheiro) i umieściłem następujący kod w filter.php

Route::filter('auth', function()
{
    // If there's no user authenticated session
    if (Auth::guest()) {
        // Flash current url to session and redirect to login page
        Session::flash('redirect', URL::full());
        return Redirect::guest('login');
    }
});

A potem w moim AuthController.php:

// Try to log the user in.
if (Auth::attempt($userdata)) {

    if ($redirect = Session::get('redirect')) {
        return Redirect::to($redirect);
    } else {
        // Redirect to homepage
        return Redirect::to('your_default_logged_in_page')->with('success', 'You have logged in successfully');
    }
} else {
    // Reflash the session data in case we are in the middle of a redirect 
    Session::reflash('redirect');

    // Redirect to the login page.
    return Redirect::to('login')->withErrors(['password' => 'Password invalid'])->withInput(Input::except('password'));
}

Zwróć uwagę, że 'redirect'dane sesji są reflasowane, jeśli występuje problem z uwierzytelnieniem. Dzięki temu przekierowanie pozostaje nienaruszone podczas jakichkolwiek wpadek logowania, ale jeśli użytkownik kliknie w dowolnym momencie, następny proces logowania nie zostanie zakłócony przez dane sesji.

Musisz także ponownie załadować dane w miejscu, w którym pojawia się formularz logowania, w AuthControllerprzeciwnym razie łańcuch zostanie zerwany:

public function showLogin()
{
    // Reflash the session data in case we are in the middle of a redirect 
    Session::reflash('redirect');

    // Show the login page
    return View::make('auth/login');
}
Joe Richards
źródło
3

Posługiwać się Redirect;

Następnie użyj tego:

return Redirect::back();
ujwal dhakal
źródło
0

Larvel 5.3 to faktycznie działało dla mnie po prostu aktualizując LoginController.php

 use Illuminate\Support\Facades\Session;
 use Illuminate\Support\Facades\URL;


public function __construct()
{
    $this->middleware('guest', ['except' => 'logout']);
    Session::set('backUrl', URL::previous());
}


public function redirectTo()
{
    return Session::get('backUrl') ? Session::get('backUrl') :   $this->redirectTo;
}

ref: https://laracasts.com/discuss/channels/laravel/redirect-to-previous-page-after-login

Nomi
źródło
0

Dla Laravela 5.5 i prawdopodobnie 5.4

W App \ Http \ Middleware \ RedirectIfAuthentified zmień redirect('/home')na redirect()->intended('/home')w funkcji uchwytu:

public function handle($request, Closure $next, $guard = null)
{
    if (Auth::guard($guard)->check()) {
        return redirect()->intended('/home');
    }

    return $next($request);
}

w App \ Http \ Controllers \ Auth \ LoginController utwórz showLoginForm()funkcję w następujący sposób:

public function showLoginForm()
{
    if(!session()->has('url.intended'))
    {
        session(['url.intended' => url()->previous()]);
    }
    return view('auth.login');
}

W ten sposób, jeśli był zamiar dla innej strony, przekieruje tam, w przeciwnym razie przekieruje do domu.

DerDare
źródło
0

Korzystam z następującego podejścia z niestandardowym kontrolerem logowania i oprogramowaniem pośrednim dla Laravel 5.7, ale mam nadzieję, że zadziała w dowolnej wersji laravel 5

  • w oprogramowaniu pośrednim

    if (Auth::check()){
        return $next($request);
    }
    else{
      return redirect()->guest(route('login'));
    }
  • wewnątrz metody logowania do kontrolera

    if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return redirect()->intended('/default');
    }
  • Jeśli musisz przekazać zamierzony adres URL stronie klienta , możesz wypróbować następujące czynności

       if (Auth::attempt(['username' => $request->username, 'password' => $request->password])) {
           $intended_url= redirect()->intended('/default')->getTargetUrl();
           $response = array(
          'status' => 'success',
          'redirectUrl' => $intended_url,
          'message' => 'Login successful.you will be redirected to home..', );
          return response()->json($response);
        } else {
            $response = array(
          'status' => 'failed',
          'message' => 'username or password is incorrect', );
         return response()->json($response);
        }
Nayeem Azad
źródło
0

Po pierwsze, powinieneś wiedzieć, w jaki sposób przekierowujesz użytkownika do trasy „logowania”:

return redirect()->guest('/signin');

Nie tak jak to:

return redirect()->intended('/signin');
Odiłow Oybek
źródło
0

Laravel obsługuje teraz tę funkcję od razu po wyjęciu z pudełka! (Wierzę od wersji 5.5 lub wcześniejszej).

Dodaj __construct()metodę do swojej, Controllerjak pokazano poniżej:

public function __construct()
{
    $this->middleware('auth');
}

Po zalogowaniu użytkownicy zostaną przekierowani na stronę, którą zamierzali odwiedzić na początku.

Możesz także dodać funkcję weryfikacji e-mail Laravela zgodnie z logiką aplikacji:

public function __construct()
{
    $this->middleware(['auth', 'verified']);
}

Dokumentacja zawiera bardzo krótki przykład:

Można również wybrać metody kontrolera, których oprogramowanie pośrednie ma dotyczyć, za pomocą opcji except lub only.

Przykład z except:

public function __construct()
{
    $this->middleware('auth', ['except' => ['index', 'show']]);
}

Przykład z only:

public function __construct()
{
    $this->middleware('auth', ['only' => ['index', 'show']]);
}

Więcej informacji na temat opcji excepti onlyoprogramowania pośredniego:

LobsterBaz
źródło
0

jeśli używasz axios lub innej biblioteki javascript AJAX, możesz pobrać adres URL i przekazać go do interfejsu

możesz to zrobić za pomocą poniższego kodu

   $default = '/';

   $location = $request->session()->pull('url.intended', $default);

    return ['status' => 200, 'location' => $location];

Zwróci ciąg sformatowany w formacie json

Emmanuel David
źródło
0

W Laravel 5.8

w App \ Http \ Controllers \ Auth \ LoginController dodaj następującą metodę

public function showLoginForm()
{
    if(!session()->has('url.intended'))
        {
            session(['url.intended' => url()->previous()]);
        }
    return view('auth.login');
}

w aplikacji \ Http \ Middleware \ RedirectIfAuthenticated zamień „return redirect ('/ home');” na następujący

 if (Auth::guard($guard)->check()) 
    {
        return redirect()->intended();
    }
Yann Boyongo
źródło
-1

Próbowałeś tego w swoim route.php?

Route::group(['middleware' => ['web']], function () {
    //
    Route::get('/','HomeController@index');
});
Arios
źródło
-1
       // Also place this code into base controller in contract function,            because ever controller extends base  controller
 if(Auth::id) {
  //here redirect your code or function
 }
if (Auth::guest()) {
       return Redirect::guest('login');
}
fajny programista
źródło
2
Podaj komentarz do kodu, aby podać kontekst. Dzięki
Suever,
-1

Oto moje rozwiązanie dla 5.1. Potrzebowałem kogoś, kto kliknie przycisk „Lubię to” w poście, zostanie przekierowany do logowania, a następnie wróci do oryginalnej strony. Jeśli byli już zalogowani, przycisk href„Lubię to” został przechwycony przez JavaScript i przekształcony w żądanie AJAX.

Przycisk jest podobny <a href="https://stackoverflow.com/like/931">Like This Post!</a>. /like/931jest obsługiwany przez LikeController, który wymaga authoprogramowania pośredniego.

W oprogramowaniu pośredniczącym Uwierzytelnij ( handle()funkcja) dodaj na początku coś takiego:

    if(!str_contains($request->session()->previousUrl(), "/auth/login")) {
        $request->session()->put('redirectURL', $request->session()->previousUrl());
        $request->session()->save();
    }

Zmień /auth/loginna dowolny adres URL do logowania. Ten kod zapisuje adres URL oryginalnej strony w sesji, chyba że jest to adres URL logowania. Jest to wymagane, ponieważ wydaje się, że to oprogramowanie pośrednie jest wywoływane dwukrotnie. Nie jestem pewien, dlaczego lub czy to prawda. Ale jeśli nie sprawdzisz tego warunku, będzie on równy poprawnej oryginalnej stronie, a następnie jakoś się da /auth/login. Jest to prawdopodobnie bardziej elegancki sposób na zrobienie tego.

Następnie w LikeControllerdowolnym kontrolerze, który obsługuje adres URL przycisku wciśniętego na oryginalnej stronie:

//some code here that adds a like to the database
//...
return redirect($request->session()->get('redirectURL'));

Ta metoda jest bardzo prosta, nie wymaga zastępowania żadnych istniejących funkcji i działa świetnie. Możliwe, że Laravel ma na to łatwiejszy sposób, ale nie jestem pewien, co to jest. Użycie tej intended()funkcji nie działa w moim przypadku, ponieważ LikeController musiał również wiedzieć, co poprzedni adres URL miał przekierować z powrotem do niego. Zasadniczo dwa poziomy przekierowania do tyłu.

Brynn Bateman
źródło
-1

Dla Laravel 5.2 (poprzednich wersji nie korzystałem)

Wklej kod do aplikacji plikowej \ Http \ Controllers \ Auth \ AurhController.php

   /**
 * Overrides method in class 'AuthenticatesUsers'
 *
 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 */
public function showLoginForm()
{
    $view = property_exists($this, 'loginView')
        ? $this->loginView : 'auth.authenticate';
    if (view()->exists($view)) {
        return view($view);
    }
    /**
     * seve the previous page in the session
     */
    $previous_url = Session::get('_previous.url');
    $ref = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
    $ref = rtrim($ref, '/');
    if ($previous_url != url('login')) {
        Session::put('referrer', $ref);
        if ($previous_url == $ref) {
            Session::put('url.intended', $ref);
        }
    }
    /**
     * seve the previous page in the session
     * end
     */
    return view('auth.login');
}
/**
 * Overrides method in class 'AuthenticatesUsers'
 *
 * @param Request $request
 * @param $throttles
 *
 * @return \Illuminate\Http\RedirectResponse
 */
protected function handleUserWasAuthenticated(Request $request, $throttles)
{
    if ($throttles) {
        $this->clearLoginAttempts($request);
    }
    if (method_exists($this, 'authenticated')) {
        return $this->authenticated($request, Auth::guard($this->getGuard())->user());
    }
    /*return to the previous page*/
    return redirect()->intended(Session::pull('referrer'));
    /*return redirect()->intended($this->redirectPath()); /*Larevel default*/
}

I zaimportuj przestrzeń nazw: use Session;

Jeśli nie wprowadziłeś żadnych zmian w aplikacji plikowej \ Http \ Controllers \ Auth \ AurhController.php, możesz po prostu zastąpić ją plikiem z GitHub

zdorovo
źródło
-1

Laravel 5.2

Jeśli używasz innego Middleware jak Admin oprogramowania pośredniego można ustawić sesję dla url.intended za pomocą tej czynności:

Zasadniczo musimy ustawić ręcznie \Session::put('url.intended', \URL::full());przekierowanie.

Przykład

  if (\Auth::guard($guard)->guest()) {
      if ($request->ajax() || $request->wantsJson()) {
         return response('Unauthorized.', 401);
      } else {
        \Session::put('url.intended', \URL::full());
        return redirect('login');
      }
  }

Podczas próby logowania

Upewnij się przy próbie logowania return \Redirect::intended('default_path');

Rashedul Islam Sagor
źródło
Po to redirect()->guest('login')jest.
Emile Bergeron,
-1

W przypadku Laravle 5.7 musisz wprowadzić zmiany w:

Oprogramowanie pośrednie> RedirectIfAuthenticated.php

Zmień to:

public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect('/admin');
        }

        return $next($request);
    }

Do tego:

public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect('/yourpath');
        }

        return $next($request);
    }

return redirect ('/ yourpath');

Książę Ahmed
źródło
Co to jest mypath? (użytkownik przechodzi do tego)
Mostafa Norzade