Back

Using Auth::check() in multiple guards


Hello,

I am trying to make a route available to both our web app and api. The problem I am having is that we have a call to Auth::check(). This works for the web routes as auth:web is the default but does not work for the api route (which is using auth:api.

At present I have got it working by extending the Request class and creating a way to detect where the request is coming from (i.e. via the web app or an API call.)

This means in the controller I can have code like this.

$guard = $request->getGuard();

    if (Auth::guard($guard)->check()) {

i.e. passing the detected guard to the call.

I don't really want have to make this check every time we need to call Auth:check or Auth::user.

Is there a way I can move my check into the Auth class itself? I cannot actually find where Auth::check is called from. I am still trying to understand Laravel so apologies if the question is dumb.

astroanu replied 1 year ago

you can use a middleware,

infact laravel comes with a middleware that does similar task. take a look at App\Http\Middleware\RedirectIfAuthenticated class

evinkuraga replied 2 months ago

@scottabailey did you ever end up finding a solution for this? I'm having this same problem. The moment I switch the default route to API, I can use the Auth::check() method, but when i switch it back to web, it ceases to work.

@Astroanu suggested implementing a middleware, but I'm not sure how this would work. Even if I run the Auth::guard('api')->check(), it doesn't give me access to the auth::check method.

Peace-N replied 2 months ago

Please Create an API Middleware and use it on the specific routes:

see below:

https://laravel.com/docs/5.6/middleware

evinkuraga replied 2 months ago

@peace-N thanks for the response. That's actually not what I was asking. I know how to create and implement middleware, I'm just wondering how to make the auth::check method available to the API route when the default guard is set to WEB.

Here's the problem, I can access the Auth::check() method when applying the auth middleware to the specific route, but that will return a non authenticated message before hitting the controller. I need to return data regardless of whether they are logged in or not, which is why I use the auth::check method and don't force the auth.

Ultimately, what I'm wondering if @scottbailey ever managed to resolve, is whether he built a middleware that works in the circumstance. I tried creating one with just this:

Auth::guard('api')->check();
return $next($request);

which didn't work. I also tried to replicate the Authenticate middleware class and tweaking it to return regardless of the auth fail, but didn't actually managed to get it to go through if it failed.

Anyone has a workable solution they can demonstrate?

In the mean time, you can use this in your controllers to check if the user is logged in with the api key:

$user = Auth::guard('api')->user();
evinkuraga replied 2 months ago

Solution found. Create a middleware with this code:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Factory as Auth;

class CheckAuth
{
	protected $auth;

	public function __construct(Auth $auth)
	{
		$this->auth = $auth;
	}

	public function handle($request, Closure $next, ...$guards)
	{
		$this->authenticate(["api"]);

		return $next($request);
	}

	protected function authenticate(array $guards)
	{
		if (empty($guards)) {
			return $this->auth->authenticate();
		}

		foreach ($guards as $guard) {
			if ($this->auth->guard($guard)->check()) {
				return $this->auth->shouldUse($guard);
			}
		}

		throw new AuthenticationException('Unauthenticated.', $guards);
	}
}

Of course, implement this inside your kelnel.php

protected $middlewareGroups = [
        'web' => [
            ...
        ],

        'api' => [
            ...
	        \App\Http\Middleware\CheckAuth::class,
        ],
    ];

Sign in to participate in this thread!



We'd like to thank these amazing companies for supporting us