Laravel Passport Route redirects to login page

2020-02-23 07:46发布

问题:

I'm using Laravel 5.3 & Passport.

When using Postman to test any route I have set in api.php file it always returns the login page. Here is an example of my testing route:

Route::get('/getKey', function() {
    return 'hello';
})->middleware('client_credentials');

Postman params:

Accept application/json
Authorization Bearer <then my key>

I have set middleware to 'auth:api' per another solution I found while searching for the answer.

protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('auth:api')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }

I've tried just about every solution that has worked for others but still no luck. Any suggestions would be much appreciated.

UPDATE So I finally got something to work. I created a consumer app and created a few test functions. I was able to consume the api, with verification of token. However, hitting this Route no longer returns my login page, but instead now returns nothing. So its still not working for whatever reason.

Route::get('/user', function (Request $request) {

    return $request->user();
})->middleware('client_credentials');

回答1:

The redirection to the defined login route is occurring in the app\Exceptions\Handler.php class.

protected function unauthenticated($request, AuthenticationException $exception)
{
    if ($request->expectsJson()) {
        return response()->json(['error' => 'Unauthenticated.'], 401);
    }

    return redirect()->guest(route('login'));
}

The function tries to detect whether it is being called from an API (it which case it returns a 401 Unauthorized reponse with JSON message) and if not it will redirect to the login page according to the comments it

Converts an authentication exception into an unauthenticated response

To resolve the issue in postman, on the request click on the Headers tab and add:

key:   Accept
value: application/json

I'm pretty new to this so am not sure whether this is a header we should be adding when testing all API calls with Postman or just a nusience with how this laravel method is setup.

Anyway this would solve your issue with being redirected to the login page, however it's a sign your underlying authentication isn't working



回答2:

You need to add Authorization: Bearer YOUR_TOKEN to your every request's header. Also, for latest version Laravel 5.5 or above. You need to add Accept: application/json to request header too.



回答3:

Add this code on Headers on postman.

key           Value
Accept        application/json


回答4:

It is coded to check whether the request comes from Ajax. In that case you will receive the following json if authentication fails:

{
"error": "Unauthenticated."
}

Otherwise it will assume you are using a browser and it will redirect to Html login page for authentication.

You can add the following header to your request to simulate an Ajax request:

X-Requested-With = XMLHttpRequest


回答5:

if you are using username instead of email for credential; insert this method at your User model:

function findForPassport($username) {
     return $this->where('username', $username)->first();
}


回答6:

From laravel 5.8 till the current 6.0 version there is a a middleware located at the app/http/Middleware which is \App\Http\Middleware\Authenticate, it has a method

redirectTo

with the code

protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return route('login');
        }
    }

Re-write this to

 protected function redirectTo($request)
    {

        if (! ($request->expectsJson() || collect($request->route()->middleware())->contains('api'))) {
            return route('login');
        }

    }

What this code does is to return a Illuminate\Routing\Redirector instance and sets it as the \Illuminate\Auth\AuthenticationException $redirectTo parameter . which is passed to \App\Exceptions@render by laravel.

At the render function you can write a logic to catch an \Illuminate\Auth\AuthenticationException exception.

Here is my own implementation

     /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {


        /**
         * Render an Authentification exception when user trying to viditing a route or 
         * Perform an action is not properly authenticated
         */
        if ($exception instanceof \Illuminate\Auth\AuthenticationException) {


            return $this->unauthenticated($request,$exception);
        }
    }

    /**
     * Convert an authentication exception into a response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function unauthenticated($request, \Illuminate\Auth\AuthenticationException $exception)
    {
        return $exception->redirectTo()
                    ? redirect()->guest($exception->redirectTo())
                    : response()->json(['message' => $exception->getMessage()], 401);
    }




回答7:

As noted in many of the answers the reason this happens is indeed the code:

if (! $request->expectsJson()) {
    return route('login');
} 

in app\Http\Middleware\Authenticate.php

An elegant solution is to wrap your api requests in Middleware that adds 'Accept: application/json' to the header of those requests.

I got this idea from this article: https://medium.com/@martin.riedweg/laravel-5-7-api-authentification-with-laravel-passport-92b909e12528



回答8:

Here is where the issue is, from these line of codes

  protected function mapApiRoutes()
{
    Route::prefix('api')
         ->middleware('auth:api')
         ->namespace($this->namespace)
         ->group(base_path('routes/api.php'));
}

eye mark

->middleware('auth:api')

The 'auth:api" middleware has the keyword AUTH === authenticated user, so what happen is all requests under this middleware even those which do not need authenticated user will require one

So when the postman make a request to routes under auth:api it will be redirected to the login page for authentifications first(to login first)

So i would kindly suggest to use auth:api middleware for routes that requires an authenticated user as per your designs and security of your app

In case you have 'auth:api" on your Http/kernel.php file under like so

 'api' => [
        'throttle:60,1',
        'bindings',
        'auth:api"

    ],

And you have designed SPA and all routes are on routes/api.php even reaching a login/signup page will require an authenticated user which is odd.

So add 'auth:api' middleware when appropriate.