Laravel: Multiple auth with same routes - laravel

I have a Laravel(5.8) application where I have 2 roles Super Admin and Admin which are saved in two different tables admins & users. They each have their own access levels respectively. However, about 95% of the routes in the entire application are same for each of them but restricted or modified according to their access levels.
For example:
Admin can only update his own profile and has the permission to Create & View.
Super Admin can play with the list of admins and has the permission of create/update/view & delete.
Therefore I have two guards users(default) = users table and admins = admins table. But when I am adding both or the guards in a same controller it just keep redirecting and display that the page is not redirecting properly
config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'member' => [
'driver' => 'session',
'provider' => 'member',
],
...
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'member' => [
'driver' => 'eloquent',
'model' => App\Member::class,
],
],
User.php
class User extends Authenticatable
{
...
public function _login($request)
{
if(\Auth::attempt([
'email' => $request->email,
'password' => $request->password
]))
{
return [
'success' => true
];
}
else
{
return [
'success' => false
];
}
}
}
Member.php
class Member extends Authenticatable
{
...
public function _login($request)
{
if(\Auth::guard('member')->attempt([
'email' => $request->email,
'password' => $request->password
]))
{
return [
'success' => true
];
}
else
{
return [
'success' => false
];
}
}
}
HomeController.php
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
echo "<pre>";
if(\Auth::user())
{
print_r(\Auth::user());
}
else if(\Auth::guard('member')->user())
{
print_r(\Auth::guard('member')->user());
}
echo "</pre>";
}
}
If I comment the auth middleware in the __construct() then it works and displays the data of the logged in user but if keep redirecting and shows the page is not redirecting properly error.

You probably want to use $this->middleware('auth:web') or $this->middleware('auth:member') so your middleware knows which guard to use.
Anything after the : is passed to the Middleware's handle() function as arguments.

Related

Transfer shopping cart from guest to user logged?

I use https://github.com/darryldecode/laravelshoppingcart
I only have authentication by username without password
The problem is the sessions
When I am a guest, the session code is for example
9ot0CjCYUQpYR10ox43A9GoHVp6vliXuFFsoZlGU
After registration it is renewed to a different code
HXTc6LXNEW79QzvrvnKwi2N3IBQWwSroBfghOznR
in config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'customers',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Modules\User\Entities\User::class,
],
'customers' => [
'driver' => 'eloquent',
'model' => Modules\User\Entities\Customer::class,
],
],
CACHE_DRIVER=redis
SESSION_DRIVER=redis
in User/Http/Controllers/AuthController.php
public function verify(VerifyCodeRequest $request)
{
$customer = $this->customer($request);
/* code etc. */
if ($customer->exists) {
auth()->login($customer,true);
}
}
in Cart/Providers/CartServiceProvider.php
public function register()
{
$this->app->singleton(Cart::class, function ($app) {
return new Cart(
$app['session'],
$app['events'],
'cart',
session()->getId(),
config('fleetcart.modules.cart.config')
);
});
}
What worked for me (original code by #liamjcooper) was creating event listeners.
namespace App\Providers;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
/* flash cart items */
\Illuminate\Auth\Events\Attempting::class => [
\App\Listeners\PrepareCartTransfer::class
],
/* add flashed cart items to authenticated user cart */
\Illuminate\Auth\Events\Login::class => [
\App\Listeners\TransferGuestCartToUser::class
]
/* end cart item */
];
then ran
php artisan event:generate
at the listeners
flash the cart content from guest
namespace App\Listeners;
class PrepareCartTransfer
public function handle(Attempting $event)
{
if (Auth::guest()) {
session()->flash('guest_cart', [
'session' => session()->getId(),
'data' => \Cart::getContent()
]);
}
}
transfer cart items to authenticated user
namespace App\Listeners;
class TransferGuestCartToUser
{
public function handle(Login $event)
{
$userCart = \Cart::getContent();
$userCartItems = $userCart->toArray();
if (session('guest_cart.data') != null ) {
$guestCart = session('guest_cart.data');
$guestCartItems = $guestCart->toArray();
}
if ($userCart->isNotEmpty() && !empty($guestCartItems)) {
$maxUserCartId = max(array_column($userCartItems, 'id'));
$guestCartItems = array_map(function ($item) use (&$maxUserCartId) {
return array_merge($item, ['id' => ++$maxUserCartId]);
}, $guestCartItems);
}
That did enough to me running stock package.

Laravel Login and redirect depending on role id

So I have login page that the admin or users can use to login. It went well until such time we have some changes and added the admin side. I only uses 1 table for all user types and I have role_id column that defines the users role. So if the role_id is 0, I have to redirect them to the dashboard page whereas if it's a user, will redirect to user page. I have tried as what is suggested in the internet but can't make it work. Here's what I have:
class UserLoginController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest:user')->except('logout');
}
public function showLoginForm()
{
return view('auth.user-login');
}
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
// if successful, then redirect to their intended location
return redirect()->intended(route('user.dashboard'));
}
// if unsuccessful, then redirect back to the login with the form data
if (! User::where('email', $request->email)->where('password', bcrypt($request->password))->first() ) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
}
public function logout()
{
Auth::guard('user')->logout();
return redirect()->route('user.login');
}
}
config/auth
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'guest' => [
'driver' => 'session',
'provider' => 'guests',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'guests' => [
'driver' => 'eloquent',
'model' => App\Guest::class,
],
],
MODEL
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $guard = 'user';
protected $fillable = [
//fillable cols
];
//change role id data type to integer
protected $casts = [
'role_id' => 'integer',
];
}
Now, where should I insert the condition to check if it's an admin or a user?
You can try it
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (!Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
$user = Auth::guard('user')->user();
if ($user->role_id === 0) {
return redirect()->route('user.dashboard');
}
return redirect()->route('user.page');
}
Check below i have edited the method of login:
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
// Over here this condition will be true when user is successfully login
// Below is the user data i have printed in that you can check the role of user which is login.
$user = Auth::user();
print_r($user);
}
// if unsuccessful, then redirect back to the login with the form data
if (! User::where('email', $request->email)->where('password', bcrypt($request->password))->first() ) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
}

different login routes and login views for student and admin

Every laravel newbie struggles with multi auth, I am no exception
I am trying to make student management system. There will two different routs for admin admin/login and for student student/login.
The student can't register itself, but he will be registered by admin.
So a student has only access to student/dashboard, registration of students will be done by the admin on admin/dashboard.
Below is the detail what I have already done:
created migration for both admin and student.
created guard for both admin and student.
modified login controller and added adminLogin and studentLogin methods.
modified RedirectIfAuthenticated middleware
Config/auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'students' => [
'driver' => 'session',
'provider' => 'students',
],
'web-admin'=>[
'driver'=>'session',
'provider'=>'admin',
],
'api' => [
'driver' => 'token',
'provider' => 'students',
'hash' => false,
],
],
'providers' => [
'students' => [
'driver' => 'eloquent',
'model' => App\Student::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
'passwords' => [
'students' => [
'provider' => 'students',
'table' => 'password_resets',
'expire' => 60,
],
'admin' => [
'provider' => 'admin',
'table' => 'password_resets',
'expire' => 60,
],
],
LoginController.php
lass LoginController extends Controller
{
use AuthenticatesUsers;
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->middleware('guest:web-admin')->except('logout');
$this->middleware('guest:students')->except('logout');
}
public function showAdminLoginForm()
{
return view('admin.login', ['url' => 'admin']);
}
public function adminLogin(Request $request)
{
$this->validate($request, [
'admin_id' => 'required',
'password' => 'required|min:8'
]);
if (Auth::guard('admin')->attempt(['admin_id' => $request->adminid, 'password' => $request->password], $request->get('remember'))) {
return redirect()->intended('/admin/dashboard');
}
return back()->withInput($request->only('admin_id', 'remember'));
}
public function showStudentLoginForm()
{
return view('student.login', ['url' => 'student']);
}
public function studentLogin(Request $request)
{
$this->validate($request, [
'roll_no' => 'required',
'password' => 'required|min:8'
]);
if (Auth::guard('writer')->attempt(['roll_no' => $request->roll_no, 'password' => $request->password], $request->get('remember'))) {
return redirect()->intended('/student/dashboard');
}
return back()->withInput($request->only('roll_no', 'remember'));
}
}
RedirectAuthenticated.php
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if('web_admin'==='$guard'){
return redirect('/admin/dashboard');
}
return redirect('/admin/login');
}
if (Auth::guard($guard)->check()) {
if('students'==='$guard'){
return redirect('/student/dashboard');
}
return redirect('/student/login');
}
return $next($request);
}
}
I have created two folders in the view, student and admin. They both have two files. login.blade.php and dashboard.blade.php
What laravel does it it shows login, and register under auth folder.
I want to give two routes one for /admin/login which return admin.login view.
Same for student /student/login which return student.login view.
I want to remove /register route and make the link to available on admin dashboard , there will be no admin register link.
Also restrict the user from accessing admin area.
**I don't want the whole code, just help me steps and way that I should follow or changes I have to make **
Finally I solved it. I didn't use php artisan make:auth, instead I did it from scratch. Created a fresh project, deleted User.php and the migration.
Created models Student.php and Admin.php along with migrations and controllers.
php artisan make:model Student -mc
php artisan make:model Admin -mc
After than I created guards, I deleted default guard (I don't know It was right to do so, but I felt that if there is no need of default guard and also it was using users table so I deleted).
Here is config/auth.php
'guards' => [
'student'=>[
'driver'=>'session',
'provider'=>'students'
],
'admin'=>[
'driver'=>'session',
'provider'=>'admins'
],
],
'providers' => [
'students'=>[
'driver'=>'eloquent',
'model'=>App\Student::class,
],
'admins'=>[
'driver'=>'eloquent',
'model'=>App\Admin::class,
]
So I have two guards student and admin.
Here is the admin model Admin.php
class Admin extends Authenticatable
{
use Notifiable;
protected $fillable = [
'firstname', 'lastname','admin_id', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
and model Student Student.php
class Student extends Authenticatable
{
use Notifiable;
protected $fillable = [
'firstname', 'lastname','admin_id', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
After this I modified AdminController.php
class AdminsController extends Controller
{
use AuthenticatesUsers;
protected $guard = 'admin';
public function showLogin(){
return view('admin.login');
}
public function dashboard(){
return view('admin.dashboard');
}
public function login(Request $request){
$this->validate($request,[
'admin_id' => 'required',
'password'=>'required|min:8',
]);
if(Auth::guard('admin')->attempt(['admin_id'=>$request['admin_id'], 'password'=>$request['password']])){
return redirect('admin/dashboard');
}
return redirect('/admin');
}
}
Then I created routes Web.php
Route::get('/', function () {
return view('welcome');
});
Route::get('/admin','AdminsController#showLogin');
Route::get('/student','StudentsController#showLogin');
Route::get('/admin/dashboard','AdminsController#dashboard');
Route::get('/student','StudentsController#showLogin');
Route::post('/admin/login','AdminsController#login');
Route::post('/student/login','StudentsController#login');
Now, at this time login works. I still need to do a lot. If any suggestion, I welcome that, please comment below.

laravel custom auth - attempt(), session

I'm learning how to create custom auth system. I created own guard Player. On my test function I'm usimg attempt() to authenticate user. Checking is passed. Then I created test2 method which is accesible only for logged user.
My Route is:
Route::get('test', 'MyController#test');
Route::get('test2', 'MyController#test2')->middleware('auth');
My Controller is:
class MyController extends Controller
{
public function test()
{
$cr = ['name' => 'pl', 'password' => 'pl'];
if (Auth::guard('player')->attempt($cr)) {
$user = Auth::guard('player')->user();
return 'ok';
}
return 'not found';
}
public function test2()
{
return 'test2';
}
}
My guard config is:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'player' => [
'driver' => 'session',
'provider' => 'player',
],
'club' => [
'driver' => 'session',
'provider' => 'club',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'player' => [
'driver' => 'eloquent',
'model' => App\Player::class,
],
'club' => [
'driver' => 'eloquent',
'model' => App\Club::class,
],
],
I want to get access to test2 route by hand (not by redirecting) after performing test function but I can't. I'm receiving Auth default login form.
Should I write my own middleware or set session manually? Please help.
You need to write you own middleware,
<?php
namespace App\Http\Middleware;
use Closure;
class RedirectIfNotPlayer
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $guard = 'player')
{
if(!auth()->guard($guard)->check()) {
return redirect(url('/player/login'));
}
return $next($request);
}
}
add this middleware to your kernel.php file, inside routeMiddleware,
'player' => \App\Http\Middleware\RedirectIfNotPlayer::class,
Then You can use your middleware in route,
Route::get('test2', 'MyController#test2')->middleware('player');
I suggest you to do like this may be this work out!
public function test()
{
$cr = ['name' => 'pl', 'password' => 'pl'];
if (Auth::guard('player')->attempt($cr)) {
$user = Auth::guard('player')->user();
return 'ok';
redirect("test2(view)");
}
You need to redirect to somewhere after login is successful to have the session persist.
make auth middleware use your guard:
Route::get('test2', 'MyController#test2')->middleware('auth:player');

Access authenticated user in a Laravel 5.4 Model

I'm building an app that has pricing. I would want to assign some special price to some specific users.
In the model that has the price, I'm trying to use an accessor to "tweak" the price like so:
public function getPriceAttribute($price)
{
dd(auth()->user()); //this returns null
if (auth()->check()) {
$user = auth()->user();
return $user->aDefinedRelationship()->first()->price;
}
return $price;
}
However auth()->user() always returns null.
I'm using the traditional Laravel authentication, no external library.
Please is there something I'm not doing right?
Any help would be appreciated.
More information:
auth.php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Api\V1\Models\User::class,
],
],
];
ThePriceModel.php
namespace App\Api\V1\Models;
use Illuminate\Database\Eloquent\Model;
class ThePriceModel extends Model
{
protected $table = 'prices';
protected $fillable = ['code', 'price'];
public function getPriceAttribute($price)
{
dd(auth()->user()); //this returns null
if (auth()->check()) {
$user = auth()->user();
return $user->aDefinedRelationship()->first()->price;
}
return $price;
}
}
After every other thing failed, I resorted to using a global config variable.
in config/constants.php:
return [
...
'user' => []
];
somewhere in my controller:
config()->set('constants.user', auth()->user());
Then in the model:
...
public function getPriceAttribute($price)
{
$user = config()->get('constants.user');
...
}
I suppose you were using API and this is why it didn't work. You could check for the user using this. You need to check API guard.
$user = \Auth::user() ?? \Auth::guard("api")->user();

Resources