Laravel 7: custom guard authentication does not work as expected - laravel

I have a multiauth project. I have the default authentication and a custom guard. At the login controller, when I make the login attempt, it authenticates as expected. However, when it gets to the homepage, the custom guard is not logged in anymore.
Users that use the custom guard already log in through an external API, so i don't want them on my users table. I just need a couple of fields to show them some content.
LoginController.php (Up to the return, attempt method returns TRUE)
...irrelevant code...
Auth::guard('ivao')->attempt(array('vid' => $user_array->vid, 'name' => $user_array->name, 'surname' => $user_array->surname), true);
Cookie::queue(Cookie::forever($this->cookie_name, $_COOKIE['ivao_token']));
Cookie::queue(Cookie::forever('vid', $user_array->vid));
return redirect('/');
...irrelevant code...
CustomProvider.php
class CustomUserProvider extends ServiceProvider implements UserProvider
{
public function retrieveById($identifier)
{
}
public function retrieveByToken($identifier, $token)
{
if(Cookie::get('rememberToken') == $token)
{
$user = new ApiUser();
$user->vid = Cookie::get('vid');
$user->name = Cookie::get('name');
$user->surname = Cookie::get('surname');
return $user;
}
else return NULL;
}
public function updateRememberToken(UserContract $user, $token)
{
if(Cookie::get('rememberToken') == $token)
{
Cookie::queue(Cookie::forever('vid', $user->vid));
Cookie::queue(Cookie::forever('name', $user->name));
Cookie::queue(Cookie::forever('surname', $user->surname));
Cookie::queue(Cookie::forever('rememberToken'), $token);
return TRUE;
}
else return FALSE;
}
public function retrieveByCredentials(array $credentials)
{
$user = new ApiUser();
$user->vid = $credentials['vid'];
$user->name = $credentials['name'];
$user->surname = $credentials['surname'];
return $user;
}
public function validateCredentials(UserContract $user, array $credentials)
{
return TRUE; //already validated at the API
}
}
Homepage Controller (Here both check methods return FALSE)
class PagesController extends Controller
{
public function index($folder= '', $page= 'inicio')
{
if( !(Auth::check() || Auth::guard('ivao')->check()) ) return redirect('/login');
...irrelevant code...
Please let me know if you need further information. Hope someone can help. I'm stuck. Thanks.

Related

Notification fake assertion not working on password reset test?

I was trying to make tests for my auth routes. For password reset route I am trying to make in which I am faking the notification module of laravel and asserting as per the docs.
This is my test file
public function testUserReceivesAnEmailWithAPasswordResetLink()
{
$this->withoutExceptionHandling();
Notification::fake();
$user = factory(User::class)->make();
$response = $this->post($this->passwordEmailPostRoute(), [
'email' => $user->email,
]);
$this->assertNotNull($token = DB::table('password_resets')->where('email', $user->email));
Notification::assertSentTo($user, PasswordReset::class);
}
While I am running this, I am getting notification was not sent error.
My User model is like this:
use Notifiable, HasApiTokens, SoftDeletes, Uuidable, Switchable, ResourceMapper;
public function role()
{
return $this->belongsTo('App\Models\Role');
}
public function company()
{
return $this->belongsTo('App\Models\Company');
}
public function AauthAccessToken()
{
return $this->hasMany('App\Models\OauthAccessToken');
}
public function isRole($role)
{
return $this->role->uuid == $role;
}
public function sendPasswordResetNotification($token)
{
$this->notify(new PasswordReset($token));
}
public function resource()
{
return $this->morphTo();
}
I can't figure whats the exact problem.

Laravel Login Validation Exception

I have used laravel auth facade for user authentication. When I try to login using wrong credentials Validation Exception is generated displaying The given data is invalid.
LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function redirectTo()
{
if(auth()->user()->role_id == 3)
return 'home';
else if (auth()->user()->role_id==2)
return 'expert';
return redirect('/logout')->with('error','You dont have User access');
}
}
I want it to redirect to login page displaying the error "Invalid Credentials". What should I do ?
In redirectTo method you must response string.
public function redirectTo()
{
if(auth()->user()->role_id == 3)
return 'home';
else if (auth()->user()->role_id==2)
return 'expert';
session()->flash('errors', 'Your message')
return 'logout';
}
Tested on Laravel 7. It's possible to do using function redirectTo() or without it's usage.
public function redirectTo()
{
$user = auth()->user();
if($user->role_id == 3) {
return 'home';
} else if ($user->role_id == 2) {
return 'expert';
}
$this->guard()->logout();
throw ValidationException::withMessages([$this->username() => __('You dont have User access.')]);
}
If you don't want to use that function, you can do it for example in function validateLogin:
protected function validateLogin(Request $request)
{
$user = User::where('email', $request->email)->first();
if ($user && $user->role_id == 3) {
$this->redirectTo = 'home';
} elseif ($user && $user->role_id == 2) {
$this->redirectTo = 'expert';
} elseif ($user) {
throw ValidationException::withMessages([$this->username() => __('You dont have User access.')]);
}
return $request->validate([
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
or in function attemptLogin:
protected function attemptLogin(Request $request)
{
$attempt = $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
if (!$attempt) {
return false;
}
$user = $this->guard()->getLastAttempted();
if ($user->role_id == 3) {
$this->redirectTo = 'home';
} elseif ($user->role_id == 2) {
$this->redirectTo = 'expert';
} else {
$this->guard()->logout();
throw ValidationException::withMessages([$this->username() => __('You dont have User access.')]);
}
return true;
}

Switching user in laravel 5.4

I am switching users in laravel and I succeeded in that as well but the thing is when I redirect the user to the dashboard after successful login it redirects to login form instead I don't know what am I doing wrong. Here is the code I am using.
public function user_reauthenticate(Request $request) {
$input = Input::all();
$data = User::where('email', $input['email'])->first();
if ($data) {
if (Hash::check($input['password'], $data->password)) {
Session::put('email', $input['email']);
$newuser = Student::find($input['new_user']);
session(['orig_user' => $data->id]);
Auth::login($newuser);
return Redirect::back();
} else {
$response = 'Wrong Credentials';
}
} else {
$response = 'User does not exist';
}
}
Can anyone help me find out the issue?
Edited
You can log in with
Auth::loginUsingId(1);
New edited
// If you have the guard student and multiple auth
$auth = auth()->guard('student');
$objAuth = $auth->loginUsingId($input['new_user']);
//Single Auth
$objAuth = Auth::loginUsingId($input['new_user']);
Add this to your top of the file:- use Illuminate\Foundation\Auth\AuthenticatesUsers;
Afterwards add a if function like below in your already completed code:-
public function user_reauthenticate(Request $request)
{
use AuthenticatesUsers;
$input = Input::all();
$data = User::where('email', $input['email'])->first();
if ($data) {
if (Hash::check($input['password'], $data->password))
{
Session::put('email', $input['email']);
$newuser = Student::find($input['new_user']);
session(['orig_user' => $data->id]);
Auth::login($newuser);
if ($this->attemptLogin($request))
{
return $this->sendLoginResponse($request);
}
}
else
{
$response = 'Wrong Credentials';
}
}
else
{
$response = 'User does not exist';
}
}
After this method override this method as follows:-
protected function authenticated(Request $request, $user)
{
return redirect()->route('dashboard');
}
Check whether your dashboard route is named dashboard or if not name it.

Passing shared variable after login with Laravel 5.5

i created a method in order to share datas with all views of my application.
For this i created a class EntityRepository where i store the datas I want to share with all views.
Those data are displayed in the layout NOT the view.
class EntityRepository
{
use App\Valuechain;
public function getEntities()
{
$vcs = Valuechain::select('valuechains.id', 'lang_valuechain.vcname', 'lang_valuechain.vcshortname')
->join('lang_valuechain', 'valuechains.id', '=', 'lang_valuechain.valuechain_id')
->join('langs', 'lang_valuechain.lang_id', '=', 'langs.id')
->where('langs.isMainlanguage', '=', '1')
->whereNull('valuechains.deleted_at')
->get();
return $vcs;
}
}
When I want to send datas to the methods I simply call the getEntities() method... For example :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
// My code here ...
return view('admin.pages.maps.sectors.index', compact('entitiesLists', 'myVars'));
}
In this specific case it works fine and i don't have issue. My issue concerns the landing page after login.
In the loginController :
I defined the redirectTo variable this way :
public $redirectTo = '/admin/home';
For specific reasons I had to override the authentificated() method in the LoginController in order to check if my app is configured or need to be setup ...
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
//return redirect()->to('admin/home');
return redirect()->action('BackOffice\StatsController#index');
}
}
The concerned index() method is sending the variable onto the view :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
return view('admin.home', compact('entitiesLists'));
}
Whatever the return i make i have error message...
Undefined variable: entitiesLists (View: C:\wamp64\www\network-dev\resources\views\admin\partials\header-hor-menu.blade.php)
I finally solved this issue by changing my routes :
Route::group(['prefix' => 'admin'], function () {
Route::get('/', function (){
$checkAuth = Auth::guard('admin')->user();
if ($checkAuth) {
return redirect('/admin/main');
}
else {
return redirect('admin/login');
}
});
});
In my loginController i changed :
public $redirectTo = '/admin/home';
to :
public $redirectTo = '/admin/main';
Finally :
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
return redirect()->to('admin/main');
}
}

Multiple Roles Filters in Laravel Controller Constructor

I have a question about filtering a controller and its actions for multiple user roles. Lets say i have a controller named MyController :
public class MyController extends \BaseController
{
public static function index()
{
}
public static function show()
{
}
public static function create()
{
}
public static function store()
{
}
public static function other()
{
}
}
And i have 2 filters for each roles, named admin and staff :
Route::filter('admin', function()
{
// Lines of code to get role
if($role != 'admin') return View::make('errors.401');
});
Route::filter('staff', function()
{
// Lines of code to get role
if($role != 'staff') return View::make('errors.401');
});
Then, i'm trying to use beforeFilter on the constructor of MyController :
public function __construct()
{
$this->beforeFilter('admin', ['only' => ['index', 'show', 'create', 'store']]);
$this->beforeFilter('staff', ['only' => ['index', 'show']]);
}
When I added the first beforeFilter, it works as I expected (when I logged in to my application as staff, I cannot access the index, show, create, and store methods). But when I added the second filter and logged in as staff again, I cannot access the index and show actions, which is I expected to be accessible by staff.
My questions are, is it possible to define filters for multiple roles in the constructor of a controller? (In this case, I want to make action index and show accessible by admin and staff, but create and store only accessible by admin) And if it is possible, how could I achieve that?
Thanks.
First you should make a controller that should handle access control ... as below
Acl Controller
class ACLController extends \BaseController {
/**
* admin access control list
* #return array
*/
private function adminACL() {
return array(
'users' => array(
'users',
'users.show',
//similar access list for admin users
),
);
}
/**
* staff access control list
* #return array
*/
private function staffACL() {
return array(
'staff' => array(
'staff',
'staff.index',
//similar access list for staff user
),
);
}
//Method that check access of related user
/**
* check access level
* #param string $value
* #return boolean
*/
public function hasAccessLevel($value) {
$user = //get user role here
if ($user->roles == 'staff') {
return TRUE;
} elseif ($user->roles == 'admin') {
$newAcl = array();
foreach ($this->adminACL() as $aclBreak) {
foreach ($aclBreak as $acl) {
$newAcl[] = $acl;
}
}
if (!in_array($value, $newAcl)) {
return FALSE;
} else {
return TRUE;
}
} else {
$newAcl = array();
foreach ($this->staffACL() as $aclBreak) {
foreach ($aclBreak as $acl) {
$newAcl[] = $acl;
}
}
if (!in_array($value, $newAcl)) {
return FALSE;
} else {
return TRUE;
}
}
}
}
Filter the access route...
Route::filter('hasAccess',function($route,$request,$value){
try{
$Routeacl = new App\Controllers\ACLController();
if(!$acl->hasAccessLevel($value))
{
return Redirect::to('admin/dashboard')->withErrors(array(Lang::get('en.user_noaccess')));
}
}catch(\Exception $e){
echo $e->getMessage();
}
});
And then in your route just check if it has access
Route::get('/', array('as' => 'index', 'before' => 'hasAccess:index', 'uses' => 'MyController#Index'));
Happy coding :)
I assume you have Admin can access all feature, and staff can access everything except "show"
This is the controller
class MyController extends \BaseController
{
public function __construct(){
$this->beforeFilter('admin', ['only' => ['show']]);
}
public function index()
{
echo "index";
}
public function show()
{
echo "show";
}
}
See in your last post, you are using public class, I believe in PHP you will just need class, in function better don't use static.
Here is the filters.php
Route::filter('admin', function()
{
// Lines of code to get role
if($role != 'admin') return "This is only for admin";
});
In the routes.php
Route::get("/my", "MyController#index");
Route::get("/show", "MyController#show");
Then try to login as admin, you will can access "index" and "show"
Then try to login as staff, you will can access "index" but cannot access "show"
Is an admin always a staff member? If so - you could just do this:
Route::filter('staff', function()
{
// Lines of code to get role
if(($role != 'staff') && ($role != 'admin'))return View::make('errors.401');
});

Resources