I am using policies to prevent users from accessing the admin panel. Only admins can be able to access the admin panel. I have created the policies and registered them in the authservice provider. The problem is when an admin logins in they are still not able to view the admin panel and instead, they return the 403 pages. where have I gone wrong?
the route in the web.php
Route::group(['prefix'=>'admin','middleware'=>(['auth','can::acessAdmins'])],function(){
Route::resource('dashboard',AdminDashboard_Controller::class);
}
the helper functions in the user model
public function hasAnyRoles($roles){
return $this->roles()->wherein('Role_name',$roles)
->first()?true:false;
}
public function hasRole($role){
return $this->roles()->wherein('Role_name',$role)
->first()?true:false;
}
Admin access policy
public function accessAdmins(user $user){
return $user->hasAnyRoles(['SuperAdmin','NormalAdmin']);
}
public function manageAdmins(user $user){
return $user->hasAnyRoles(['SuperAdmin']);
}
You should change the route to this:
Route::group(['prefix'=>'admin','middleware'=>(['auth','can:accessAdmins'])],function(){
Route::resource('dashboard',AdminDashboard_Controller::class);
}
The can::accessAdmins to can:accessAdmins, multiple typos.
Also see https://laravel.com/docs/8.x/middleware#middleware-parameters for more information on parameters.
And besides that you should make sure that the authorized user has the right roles.
Related
I want to redirect a user to user-dashboard after login while redirect an admin to admin-dashboard after login in Laravel 9. How can i achieve this?
If you are using use Illuminate\Foundation\Auth\AuthenticatesUsers; in your loginController you can do:
Assuming you are using Roles Package, you can do the check with HasRole or whatever field/method your project has..
public function authenticated()
{
if(auth()->user()->hasRole('admin'))
{
return redirect('/admin-dashboard');
}
return redirect('/user-dashboard');
}
I have 5 projects which are successfully deployed.... i need to give access to the user by single login to all these projects...
For example : I have 5 web app seprately which are deployed as
https://example.com/project1
https://example.com/project2
https://example.com/project3
https://example.com/project4
https://example.com/project5
and have their separate sql...
I need to login the user at very first and then the user can access all these web app and their working should go on with their respective sql....
these projects are created on laravel so, Right now the laravel auth is working and they have their own login system
All i need is to login user once and they can access all these apps
and user should login with 6th SQL(means another SQL)
In same situation, i made one more project only for authentification with Laravel Passport and add this project as socialite provider to other applications.
With this flow you have one entry point and user management for all projects.
First - make auth project. You need Laravel and Laravel Passport. See docs here. Optional - make user management ui (adding, removing, etc). Goal - users can login with their login/password.
Second - add ability to login for other projects with laravel/socialite.
Install laravel/socialite and socialiteproviders/manager
Create your own provider for your auth project - to example see the docs in socialiteproviders/manager
Implement LoginController in your apps for socialite. Some example:
class LoginController extends Controller
{
// Custom service for work with socialite - create or find users, etc
private SocialiteService $service;
public function __construct(SocialiteService $service)
{
$this->middleware('guest')->except(['logout', 'callback']);
$this->service = $service;
}
public function showLoginForm()
{
return view('pages.login');
}
public function login()
{
return $this->service->redirectToAuth();
}
public function callback(Request $request)
{
try{
$user = $this->service->getUser($request);
auth()->login($user);
return redirect()->route('index');
}catch (SocialiteException $exception){
return redirect()->route('login')->withErrors([
'error' => $exception->getMessage(),
'error_description' => $exception->getErrorDescription()
]);
}
}
public function logout(Request $request)
{
auth()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
}
}
And after that you have SSO for all your apps with dedicated auth service.
Hint: create a private package with provider, service and all you auth logic. With this you can simply add this auth flow to feature projects and avoid duplicated code.
I want to implement a system where 6 types of users exist. So one is 'customer' who will login by a route like /login and rest of 5 users are admins and only they will be login using another route /system/base-admin. However, 'customer' never login with the /system/base-admin route if anyhow can known this route. And both route have different login form and if they failed to login 'customer' will be redirected /login and admins /system/base-admin.
I know about $guard and middleware check.
Question: How can i implement above scenario and how react professionals with this scenario?
Route::get('/login','CustomerLoginController#processLogin')->name('customer.login');
Route::get('/system/base-admin', 'AdminLoginController#processAdminLogin')->name('system.admin')
My Controller Looks like
public function processLogin(){ return view('customer.login');}
public function processAdminLogin(){ return view('admin.login')}
Thank you in advance.
The only reason I see to have different endpoints for login is to have different views.
Copy your Auth\LoginController, change $redirectTo to redirect to your admin panel. Overwrite AuthenticatesUsers\showLoginForm to show your admin form and update middleware in __construct.
Protect all your admin routes with admin middleware.
Now. Your users CAN login to your panel. BUT nothing will happen since they don't have access.
If you want to show them some kind of message when they try you can overwrite AuthenticatesUsers\login method with something like this
...
if ($this->attemptLogin($request)) {
if(!auth()->user()->isAdmin()){
throw ValidationException::withMessages([
$this->username() => 'You don\'t have access to this page',
]);
}
return $this->sendLoginResponse($request);
}
...
I have a dashboard view that shows certain contain depending on which user is viewing, whether it be an admin or just a regular user.
I can get my admins onto that page, but regular users aren't able to currently because of my middleware guard.
class DashboardController extends Controller {
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('dashboard.index');
}
}
The following code checks on each DashboardController call for auth:admins, but I want regular users to access this too, is there a way to check the auth middleware twice like so?
$this->middleware(['auth:admin','auth']);
So ideally it will check if you're an admin or just a regular auth user.
Also on my view page, when accessing properties of an admin I'm using:
{{ Auth::user()->admin_username }}
Is this normal? I have an admin Model but I'm still accessing it via Auth::user() which feels strange to me, shouldn't it be Auth::admin()->admin_username
Accessing a particular page for users with differing roles is more suited for laravels gates and policy authorization mechanisms.
https://laravel.com/docs/5.5/authorization#writing-gates
These allow you to write fine tuned rules for each use case you have. Simple gates can be defined as closures within your application AuthServiceProvider. For example:
public function boot()
{
$this->registerPolicies();
Gate::define('access-dashboard', function ($user, $post) {
return auth()->check() && (auth()->user()->hasRole('admin') || auth()->user()->hasRole('regular'));
});
}
Then you can use the gate facade wherever necessary, for instance a controller method or constructor.
if (Gate::allows('access-dashboard', $model)) {
// The current user can access dashboard, load their data
}
Alternatively use the can or cant helpers on the user model directly.
if (auth()->user()->can('access-dashboard')) {
//
}
Of course, you can achieve similar via middleware, the advantage of using the above is you can authorize actions at specific points in your code as well as reusability.
As for for last question, as you have it written is correct.
{{ Auth::user()->admin_username }}
Auth::user() or auth()->user() simply returns the currently authenticated user, regardless of their role.
Policies will never work without auth middleware
Assume we´ve got a User and Conversation model with a many-to-many relation.
class User extends Model ... {
public function conversations()
{
return $this->belongsToMany('App\Conversation');
}
}
class Conversation extends Model {
public function users()
{
return $this->belongsToMany('App\User');
}
}
Besides authentication (logging in) which comes out of the box with laravel: How can I protect a specific conversation route for it´s related users?
Which would be the most maintainable way to achieve this? Middleware? Guard? Route model binding? ... right now I´m a bit lost ...
Good question. In this case you'd be best off using Laravel's authorization features. Here are the differences:
Middleware: used to run logic based on either routes or logged in / logged out state. So, if you want to block the conversations entirely from non-logged in users, use a middleware.
Authorization (policies): not to be confused with authentication, is intended for cases where the rules to block someone is not based on route but on some other, more specific reason. These reasons can be anything from roles, to teams, entity ownership, and so on. If you wanted to hide a conversation to only those in the conversation, you can create a policy that kicks the user back to their previous page if they were not in the conversation.
Here's a quick policy you might create:
class ConversationPolicy {
public function view(User $user, Conversation $conv) {
return in_array($user->id, $conv->users->pluck('id'));
}
}
You could check your policy in a controller like the following:
if($request->user()->can('view', $conversation))
{
return view('conversation', ['conversation' => $conversation]);
}
return back()->withError('You are not authorized to view this conversation');
Just be aware you'll have to bind this policy in the AuthServiceProvider before it can be used.