How do I capture a protected page's url in query string? - php

Beware with me for a second as I try to lay the background to my issue.
So I having using the python web framework Flask close to a year now and it has a wonderful extension called Flask-Login that helps provide user session management kind of like this in laravel.
Having said all that, there is a certain feature in Flask-Login that provides the functionality that when a user is not logged or signed in and tries to access that a page that requires one to be authenticated for example /create_post, they will be redirected back to the login page with that page encoded in the query string like /login?next=%2Fcreate_post.
Am trying to implement the same feature in a laravel project that am working on so I can redirect the user to the page they probably wanted to go to in the first place or to a different route in case that query string doesn't exist and I cannot seem to find where to put my code to do just that and I don't want to mess with anything in the vendor directory(because of the obvious issues that come with that), and I have tried manipulating the file app/Http/Middleware/RedirectIfAuthenticated.php by doing what is below but with no success.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/');
}
$previous_url = url()->previous(); // how do I insert this in query string
return $next($request);
}
Will I have to create my own middleware or is there another way of implementing this kind of feature in laravel?
NOTE: I am not using the default laravel authentication system. I have created my own controller SessionsController to handle logins which contains the below code.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class SessionsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['create', 'login']);
}
public function create()
{
$data = [
'title' => 'Login',
'body_class' => 'hold-transition login-page',
];
return view('auth.login', $data);
}
public function login(Request $request)
{
$this->validate($request, [
'username' => 'required',
'password' => 'required',
]);
$user = User::checkCredentials($request->username, $request->password);
if (!$user) {
return back()->with([
'class' => 'alert-danger',
'message' => 'Please check your credentials',
]);
}
// set session active flag to true
$user->session_active = true;
$user->save();
auth()->login($user);
return redirect()->route('dashboard');
}
public function destroy()
{
$user = auth()->user();
$user->last_login = date('Y-m-d H:i:s');
$user->session_active = false;
$user->save();
auth()->logout();
return redirect()->route('login')->with([
'class' => 'alert-success',
'message' => 'You logged out successfully',
]);
}
}
Thank you.

I managed to somewhat solve my issue even though I didn't use query strings as I had wanted.
I create a helper function get_previous_url as shown below
/**
* Gets the previous url
*
* #return null|string
*/
function get_previous_url()
{
$host = $_SERVER['HTTP_HOST'];
$previous_url = url()->previous();
// check if previous url is from the same host
if (!str_contains($previous_url, $host)) {
return null;
}
// get the previous url route
list(, $route) = explode($host, $previous_url);
// make sure the route is not the index, login or logout route
if (in_array(substr($route, 1), ['', 'login', 'logout'])) {
$route = '';
}
return $route;
}
And then I called the same function in my SessionsController class in the create method by doing this
public function create()
{
$previous_url = get_previous_url();
if ($previous_url) {
session(['previous_url' => $previous_url]);
}
...
}
And then I changed my login method to
public function login(Request $request)
{
...
$redirect = redirect()->route('dashboard'); // '/'
if (session()->has('previous_url')) {
$redirect = redirect(session()->pull('previous_url'));
}
return $redirect;
}

Related

Route [events] not defined using laravel

I want when I type the address http://localhost/agendab/public or when I open my web application, it will redirect directly to login, or when I click on disconnect, it will redirect to login.
web.php
Auth::routes();
Route::resource('events', 'EventController')->middleware('auth');
loginController.php
protected $redirectTo = '/events';
public function login(Request $request)
{
$input = $request->all();
$this->validate($request, [
'name' => 'required',
'password' => 'required',
]);
$fieldType = filter_var($request->name, FILTER_VALIDATE_EMAIL) ? 'email' : 'name';
if(auth()->attempt(array($fieldType => $input['name'], 'password' => $input['password'])))
{
return redirect()->route('events');
}else{
return redirect()->route('login')
->with('error','Email-Address And Password Are Wrong.');
}
}
Http/Middleware/RedirectIfAuthenticated.php
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/events');
}
return $next($request);
}
When you use Laravel resources, you need pre-defined way to call. Ex for the index you have to call events.index, if update then events.update...
In case you're calling a custom route in the same EventsController the defied it before the resource route.
In RedirectIfAuthenticated.php
if (Auth::guard($guard)->check()) {
return redirect('/events.index');
}
or
return Redirect::route('events.index'); #using facade
return redirect()->route('events.index'); #using helper class
FYK
HTTP Redirects
Actions Handled By Resource Controller
Resource Controllers
Redirect proper route name
return redirect()->route('events.index'); // loginController.php

I want to visit homepage as a guest but facing login page continuously in Laravel

I'm facing login page again and again when try to go to the homepage. I didn't add any middleware to homepage route but still I'm facing this issue.
My Login Controller
protected $redirectTo = '/';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function redirectToProvider()
{
return Socialite::driver(request()->provider)->redirect();
}
public function handleProviderCallback()
{
$provider = request()->provider;
$providerUser = Socialite::driver($provider)->user();
if($providerUser->getEmail() == null) {
$user = User::where($provider . '_id', $providerUser->getId())->first();
} else {
$user = User::where('email', $providerUser->getEmail())->first();
}
if($user && $user->$provider . '_id' == null) {
dd('test');
$user->update([$provider . '_id' => $providerUser->getId()]);
}
if(!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
$provider . '_id' => $providerUser->getId(),
]);
}
auth()->login($user, true);
return redirect($this->redirectTo);
// $user->token;
}
public function showLoginForm()
{
session()->put('previousUrl', url()->previous());
return view('auth.login');
}
public function redirectTo()
{
return str_replace(url('/'), '', session()->get('previousUrl', '/'));
}
I don't know the issue is in controller or in routes.
Routes
Route::get('/', 'WelcomePageController#index')->name('welcome');
Auth::routes();
Route::get('/login/{provider}', 'Auth\LoginController#redirectToProvider');
Route::get('/login/{provider}/callback', 'Auth\LoginController#handleProviderCallback');
I can visit the homepage only when I logged in but I want to see it as a guest.
The home route is protected, you can see this in construct method of HomeController. To make it unprotected, try to comment the line in constrct method.
To prevent errors in home view, you have to edit this view too.

How to redirect from google drive in laravel

I'm using google drive in my project for login with google.
It's working fine for me, but the problem is when user select email, in callback method user have to redirect to '/', but user will redirect to home, this is callback method :
public function callback(Request $request)
{
$googleUser = Socialite::driver('google')->stateless()->user();
$user = User::where('email', $googleUser->email)->first();
if (!$user) {
$user = User::create([
'name' => $googleUser->name,
'email' => $googleUser->email,
'password' => bcrypt(\Str::random(16))
]);
}
auth()->loginUsingId($user->id);
return $this->loggedIn($request, $user) ?: redirect(route('login'));
}
It's ok for next time user login with google, but for the first time redirect to home.
And in loggedIn function for the first time returned false because two_factor_type is off in default :
public function loggedIn(Request $request, $user)
{
if ($user->two_factor_type === 'on') {
auth()->logout();
$request->session()->flash('auth', [
'user_id' => $user->id,
'remember' => $request->has('remember')
]);
if ($user->two_factor_type === 'on') {
$code = ActiveCode::generateCode($user);
//TODO send sms
}
return redirect(route('login.twoFactor'));
}
return false;
}
Even in my LoginController or RegisterController i changed this :
protected $redirectTo = RouteServiceProvider::HOME;
To this :
protected $redirectTo = '/';
So why it will redirect to home ?
in app/Http/Controllers/Auth/LoginController check if the controller protected with middleware, e.g:
public function __construct()
{
$this->middleware('guest')->except('logout');
//meaning if there is user authenticated not guest,
//when he hit function other than logout()
//will be redirected to default landing, in code below
}
in app/Http/Middleware/RedirectIfAuthenticated will check if current auth()->user() is authenticated
change the default code to :
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home'); // here change the default redirected
}
return $next($request);
}
please check route file maybe in route file your '/' path will return home page view like below...
Route::get('/', function ()
{
return view('welcome');
});
so please try to change this with your need.
or please remove below line from your callback function
return $this->loggedIn($request, $user)

Laravel Socialite Remember Me

I am using Socialite for user logins and I would like to set a remember_token to remember the user when they login through Socialite.
Right now I have the following service to create or log the user in:
class SocialAccountService {
public function createOrGetUser(ProviderUser $providerUser) {
$account = SocialAccount::whereProvider('google')
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'google'
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName()
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
It is called with the following controller:
class AuthController extends Controller {
public function logout() {
Auth::logout();
return redirect('/');
}
public function redirectToGoogle() {
return Socialite::driver('google')->redirect();
}
public function handleGoogleCallback(SocialAccountService $service) {
$user = $service->createOrGetUser(Socialite::driver('google')->user());
auth()->login($user);
return redirect('/');
}
}
The issue is that when the user comes back they are not remembered and automatically logged in. How can I do this with Socialite?
According to the documentation, passing true as the second argument of login() will set the remember token.
// Login and "remember" the given user... Auth::login($user, true);
The Auth facade and auth() helper function access the same object.

Laravel-5 redirect within authorize() function on form requests

Is it possible for me to create a redirect from within the authorize() function on a request? I have tried the following code, but it doesn't fulfill the redirect request. Can anyone shed any light on this?
Thanks.
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Reserve;
use Cookie;
use Config;
class ClassVoucherCheckoutRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Reserve $reserve, Cookie $cookie)
{
if((!$cookie->has(Config::get('app.cookie_name'))) || ($reserve->where('cookie_id', $cookie->get(Config::get('app.cookie_name')))->count() == 0))
{
return redirect()->to('butchery-voucher')->withErrors('Your reservation has expired. Places can only be held for up to 30 minutes.');
}
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
];
}
}
I also have the same issue, I did not find any solution yet but I have do this by an another way, I know this is not the right solution but may be help for now.
My problem is: I need to register an user if any other user with same fb_id did not exists in database. But I was unable to check this condition because the middelware execute before the controller and it returns me the fb_id already taken error.
This is my UserController:
public function createUser (UserRequest $request) {
/** here I need to redirect user if the given `fb_id` is already exists
before it was always returning the `fb_id` exists error before executing
the following code, because all input filtered by the `UserRequest` middleware
I have changed the `UserRequest.php` to execute the following code.
**/
$fb_id = Input::get('fb_id');
$user = $this->user->getUserWhereFbIdIn([$fb_id]);
if(sizeof($user) > 0){
return Response::json(['result' => true, 'error' => false, 'message' => 'User exists', 'data' => $user]);
}
// insert user code is here
}
UserRequest.php:
public function authorize()
{
return true;
}
public function rules()
{
$fb_id = Input::get('fb_id');
$user = User::where('fb_id', $fb_id)->get()->toArray();
if(sizeof($user) > 0){
return [];
}
return [
'fb_id' => 'required|unique:users',
'username' => 'required|unique:users',
'email' => 'required|unique:users',
'image' => 'required',
'device_id' => 'required',
'status' => 'required',
];
}
I think the most elegant solution is to make the authorize() return false when you want to redirect, and override the forbiddenResponse() method on the FormRequest class. The drawback is that you'll either have to perform the condition logic twice, or set a state variable.
class MyRequest extends FormRequest
{
public function authorize(): bool
{
return Auth::user()->hasNoEmail() ? false : true;
}
public function forbiddenResponse(): Response
{
if Auth::user()->hasNoEmail() return redirect(route('user.should_provide_email'));
return parent::forbiddenResponse();
}
public function rules(): array
{
return [];
}
}
Of course, the argument could be made that such redirects should always take place in a middleware applied to specific groups of routes, but having the option to do it in a Request class can be nice.

Categories