I am trying to make a Laravel website that uses
Laravel's Auth package. I'm using Laravel 5.3.2.
I have created a field in user table called role.
Now I want to know how to check the users role during the authentication process and then redirect to a required view based on the role.
Please help me figure out how this would be possible.
Thank you very much in advance.
When a user logs in, this is done through your LoginController.php which is located at app\Http\Controllers\Auth
This controller uses a trait called AuthenticatesUsers.
This trait has a method called authenticated() which by default is empty. This method is called if it's not empty by the trait - after all the necessary loggin in stuff has been done.
You could override this method in your AuthenticationController.php and add the functionality you are asking for. An example would be:
// You actually get an Auth\User object passed to you by the trait!
public function authenticated(Request $request, $user)
{
if($user->role == 'admin') {
// You could do anything here
return redirect()->route('admin-dashboard');
} else {
return redirect()->route('home');
}
}
Beside solution overriding some default Laravel method. I suggest an other approach: redirect user to a route which is responsible for redirect user base on user's role
In AuthController
protected $redirectTo = '/redirect';
In routes
Route::get('redirect', function(){
switch(auth()->user()->role){
case 1:
return redirect()->to();
break;
case 2:
return redirect()->to();
break;
}
})
Related
I'm really new to laravel and have been reading the documentations and tutorials. I'm planning on making an app that has 2 roles, admin and user. I modified my User model to have the column 'isAdmin' with boolean value since I only need 2 roles. How do I perform a check on this attribute during auth? Thank you.
TO answer your question, first of all to make protect any route using the auth middleware which ensures a user is authenticated (logged in) before they can access the route, you simply need to add the auth middleware.
e.g
web.php
<?php
Route::middleware('auth')->group(function(){
//All Routes which needs user to be logged in
});
or
//Individiual Route Middleware
Route::get('/path/to', 'controller#instance')->middleware('auth');
As for checking user role, you can basically create a middleware for this using the following steps:
run your php artisan make:middleware IsAdminMiddleware
open your IsAdminMiddleware and add this code inside the handle function:
public function handle($request, Closure $next)
{
if(!Auth::check()){
return redirect()->route('login');
}
if(Auth::user()->isAdmin == true){
return $next($request);
}
return redirect()->back()->with('unauthorised', 'You are
unauthorised to access this page');
}
I'm using Laravel 5.5 and I'm trying to use Gate facade to allow admins to access resources like users. First, I define a gate in AuthServiceProvider.php like following:
Gate::define('view-users', 'App\Policies\UserPolicy#view');
Then, I write view method in Policy class like this:
public function view(Admin $admin, User $user)
{
return true;
}
And, I apply the authorization like following:
//UsersController.php
$user = User::first();
if (Gate::allows('view-users', $user)) {
$users = User::all();
return view('admin.users.list', compact('users'));
}
return abort(403);
I note that, the $user argument is useless variable and I don't need it to perform authorization.
By the way, when I use allows() method of Gate facade, it always returns false. While, when I use denies() instead, these steps work fine.
what's wrong with allows() method?!
However, corresponding to the Laravel Docs, I tested other ways to apply authorization via middleware(), Model or authorize(). But, I got the same result.
Edit:
I should note that I'm using custom guard named web_admin
Thanks for any help.
Change your policy method to this:
public function view(User $user)
{
return $user->isAdmin;
}
The first argument of the policy method is always the current authenticated user. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate Closure:
if (Gate::allows('view-users')) {
// The current user can view all users...
}
If you want to check if the current user can update a specific user your policy method would be:
public function update(User $authenticatedUser, User $beeingEditedUser)
{
return $authenticatedUser->isAdmin;
}
Then authorize like this:
if (Gate::allows('update-user', $beeingEditedUser)) {
// The current user can update the user...
}
If you're using custom guard (according to your comment), you may have 2 options:
Use forUser method:
use Illuminate\Support\Facades\Auth;
if (Gate::forUser(Auth::guard('web_admin')->user())->allows('view-users')) {
// The current user can view all users...
}
Protecting the routes, specifying the guard:
Route::middleware('auth:web_admin')->group(function () {
Route::get('/users', 'UserController#index');
});
This causes Larvel to set your default auth driver and resolve the auth user based on your custom guard.
I have three different types of users in my users table and after each success full login each specific type of user needs to be redirected to specific page according to role assigned in user table I read the documentation and tried different methods like redirectTo and protected properties. But they did not work for me.
If any one have a better solution to come up with this problem please share.
Note : please do not give route solutions.
In Laravel 5.3 you can override authenticated() method in LoginController.php. For example:
protected function authenticated()
{
if (auth()->user()->type === 1) {
return redirect()->route('admin.dashboard');
} elseif (auth()->user()->type === 2) {
return redirect()->route('client.dashboard');
}
}
I have a very simple problem. I just want to direct the user to somewhere other than '/home' after they login. This is not difficult if you can alter the spark software and retain those changes in every deployment. However, composer reinstalls everything when things are deployed and it is generally bad practice to make changes to core vendor software.
This seems like it should be a very basic and simple thing for the creators to work into the software. So, how do I do it?
I have tried ...
Altering the redirectTo and redirectPath variables in the auth controller and the password controller in my app.
Adding a login controller to my app - independent of spark - and then resetting the same variables.
Attempting to call the afterLoginRedirectTo and afterAuthRedirectTo functions in the Spark service provider. This returned an error indicating that the functions did not exist.
Not sure where to go from here.
After having the same issue I've done some digging and found a way of setting something other than home, I've changed a fair bit of stuff, but hopefully this works for you too!
TLDR
Spark::afterLoginRedirectTo('somenewplace');
Option 1
The variable used is: $afterLoginRedirectTo from vendor\laravel\spark\src\Configuration\ManagesAppOptions.php
You can set this within the SparkServiceProvider#boot method:
Spark::afterLoginRedirectTo('somenewplace');
Spark has its own LoginController \vendor\laravel\spark\src\Http\Controllers\Auth\LoginController.php
which has an authenticated method to handle the two factor auth settings:
if (Spark::usesTwoFactorAuth() && $user->uses_two_factor_auth) {
return $this->redirectForTwoFactorAuth($request, $user);
}
return redirect()->intended($this->redirectPath());
RedirectPath() is from the RedirectsUsers trait which is still in vendor and does the following:
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
redirectTo in the LoginController is set in the construct method:
$this->redirectTo = Spark::afterLoginRedirect();
Option 2
Create a new route to override the login function.
in web.php specify a new route for post login:
Route::post('/login', 'Auth\NewLoginController#login');
You can then extend the LoginController and override the authenticated method:
class LoginController extends \Laravel\Spark\Http\Controllers\Auth\LoginController
{
public function authenticated(Request $request, $user)
{
/**
* #var $user User
* Set some logic here of your own for new redirect location
*/
if ($user->last_page_accessed != null) {
$this->redirectTo = $user->last_page_accessed;
}
return parent::authenticated($request, $user);
}
}
I'm having my first interaction with the core laravel code so I want to be careful not to break anything.
In my project, my users also correspond to person records (via user->person_id), so I have a get_person_from_user() function that takes the \Auth::user() (conveniently accessible anywhere) and returns the person object, so I can grab the person record for the authenticated user from any controller and pass it to a view.
The problem: there's a piece of data from the person record that I'd like to include in a nav partial in my default blade view (which gets extended by a bunch of different views), so it's the one case where I'm not going through a controller first. I'm unclear on how I can make the logged in user's person record available here. Any suggestions?
I think I need to add some step after the user logs in, to save the person record (globally? in the session?) so it's generally accessible. The login stuff happens in AuthenticatesUsers.php, and reading around it sounds like I'll want to add an override of postLogin to my AuthController.
But I tried copying that function from AuthenticatesUsers.php into my AuthController (not adding anything else to it yet), and AuthController gives me a new error when I try to log in:
ReflectionException in RouteDependencyResolverTrait.php line 81:
Class App\Http\Controllers\Auth\Request does not exist
Any advice on a good way to go about accessing the person object for the authenticated user, when I don't have a controller to pass it along?
You can setup the correct relationship on the User model to Person model.
public function person()
{
return $this->belongsTo(Person::class);
}
Then you can do:
Auth::user()->person;
For having a variable available to a particular view you can use a View Composer. (You can create and register a Service Provider and add this to the register method.) Potentially something like this:
view()->composer('someview', function ($view) {
if ($user = Auth::user()) {
$somevar = $user->person->somevar;
} else {
$somevar = null; // or some default
}
$view->with('somevar', $somevar);
});
If this view is also used in a scenario where someone doesn't have to be authed you will want to check if Auth::user() is null before trying to use the relationship.
Laravel Docs - Views - View Composers
I suggest you to use Eloquent relation
User.php
public function person()
{
return $this->belongsTo('NAMESPACE_TO_YOUR_MODEL\Person'); //also you can specify FK, more info in docs
}
then you can access Auth facade in your view
Auth::user()->person