I define new admin
guard:
'guards' => [
...
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
...
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
I also create new Booking
policy and register in AuthServiceProvider:
protected $policies = [
'App\Booking' => 'App\Policies\Admin\BookingPolicy',
];
BookingPolicy has update
method:
public function update($user, $booking)
{
...
}
When I call $this->authorize('update', $booking)
in controller, $user is an instance of AppUser. But I need to authorize the authenticated admin. I try to type-hint the parameter:
public function update(\App\Admin $user, $booking)
{
...
}
It throws an error:
Type error: Argument 1 passed to App\Policies\Admin\BookingPolicy::edit() must be an instance of App\Admin, instance of App\User given
How can we implement a function to change guard
when working with a specific policy or ability.
Thanks
From the documentation: https://laravel.com/docs/5.2/authorization#controller-authorization
The AuthorizesRequests trait also provides the authorizeForUser method to authorize an action on a user that is not the currently authenticated user:
$this->authorizeForUser($user, 'update', $post);
Gate::forUser()
should get the guard instance for the given user.
Gate::forUser() should get the guard instance for the given user.
But you can't specify that for blade making blade directives useless when using multi-auth.
Thanks all.
Just had a very similar issue trying to handle fully independent auth for admins and customers (different DB models and drivers). What got the @can
blade helpers working for me was to update the userResolver closure when my custom auth provider got instantiated. This is in the boot() method of my AuthServiceProvider class. Basically, I supply a default guard that's consistent with the guard being used for that type of auth. In my case, each request is fully served by one or the other provider - never both. So, this works nicely.
\Auth::provider('customer_auth', function ($app, array $config) {
$app['auth']->resolveUsersUsing(function ($guard = 'customer') use ($app) {
return $app['auth']->guard($guard)->user();
});
return new CustomerUserProvider($app['hash'], $config['model']);
});
\Auth::provider('admin_auth', function ($app, array $config) {
$app['auth']->resolveUsersUsing(function ($guard = 'admin') use ($app) {
return $app['auth']->guard($guard)->user();
});
return new AdminUserProvider($app['hash'], $config['model']);
});
I have same problem. Maybe we can add a guard attribute to the controller.
My solution is adding that line to middleware
config()->set('auth.defaults.guard','panel');
@drtzack Thanks for the solution. I place the code on Authenticate
middleware:
config()->set('auth.defaults.guard', $guard);
With this I can simply use Auth::user()
instead of Auth::guard('custom_guard')->user()
to access logged in user on different guard.
Hope that we can set guard attribute on a controller as you suggested.
If anyone else is trying to do this, I wrote a solution to allow setting the guard per route group.
Add this to your AppServiceProvider's boot method:
$this->app['router']->matched(function (\Illuminate\Routing\Events\RouteMatched $e) {
$route = $e->route;
if (!array_has($route->getAction(), 'guard')) {
return;
}
$routeGuard = array_get($route->getAction(), 'guard');
$this->app['auth']->resolveUsersUsing(function ($guard = null) use ($routeGuard) {
return $this->app['auth']->guard($routeGuard)->user();
});
$this->app['auth']->setDefaultDriver($routeGuard);
});
Now you can specify the guard like this:
Route::group(['guard' => 'my-guard'], function () {
// ...
});
@yuloh This is exactly what I was looking for!, took me forever to figure this one out!
In 5.3 the auth middleware does this automatically. So if you do auth:api
the api guard will be used as the default. 馃榾
@yuloh there is still an issue if you don't want to use a guard for the api, so for example you want to allow users and guests. You still need a way to change the default Auth Guard to api so that Auth:user() works everywhere as expected, e.g. in Policies.
We experienced this bug, too.
Our configuration has multiple auth guards, and inside a route that uses the non-default auth guard, Auth::user()
did never work because it tried to fetch the user with the default guard.
yuloh's hack works very fine. Thanks!
@malhal do you have an example of how this works with routes that can accept multiple guards?
@yuloh, Is there a way I can specify which login page will be redirected if the user is not authenticated with laravel 5.3?
I can't use auth: admin
because if it is not logged in, it will be redirected to "/login" and not "/admin/ login".
@jamesgraham apologies for the delay I'm not sure about multiple guards.
@lucassena - not sure if that's what you're after, but you can specify which page user is redirected to (if not authenticated) based on the guard from within the App\Exceptions\Handler::unauthenticated
- here's what I've got:
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$route = in_array('admin', $exception->guards())
? route('admin.login')
: route('front.login');
return redirect()->guest($route);
}
Also, for the App\Http\Middleware\RedirectIfAuthenticated
I've used $guard
arguments to dictate which route should be used, but this obviously depends on how you name your routes:
public function handle($request, Closure $next, $guard = null)
{
$path = $guard ?: 'front';
if (Auth::guard($guard)->check()) {
return redirect(route($path.'.dashboard'));
}
return $next($request);
}
Alternatively you could use some config file, which stores these and again - use guard name to select individual path by index.
Thankyou, @sebastiansulinski! That's exactly what I did. Anyway, thanks for your response, I'm glad that I had followed the right path!
No problem at all @lucassena - I'm glad you managed to resolve it.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Application;
class AuthGuard
{
/**
* The application implementation.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct(Application $app)
{
$this->app = $app;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $guard = 'web')
{
$this->app['auth']->setDefaultDriver($guard);
return $next($request);
}
}
Route::group([
'prefix' => '',
'middleware' => ['web', 'auth.guard:admin'],
], function ($router) {
});
Most helpful comment
If anyone else is trying to do this, I wrote a solution to allow setting the guard per route group.
Add this to your AppServiceProvider's boot method:
Now you can specify the guard like this: