Laravel API 身份验证(Passport),从后应用程序/json 中获取用户 ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49414348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 17:32:47  来源:igfitidea点击:

Laravel API Authentication (Passport), Get user ID from a post application/json

laravelauthenticationlaravel-passport

提问by LKirin

My client is send a post application/json that has a accessToken in the json file. How do I verify the user and get the user id?

我的客户端发送一个 post application/json,在 json 文件中有一个 accessToken。如何验证用户并获取用户 ID?

Here is my api.php file:

这是我的 api.php 文件:

<?php
use Illuminate\Http\Request;
/* API Routes */

Route::get('/user', function (Request $request) {
   return $request->user();
})->middleware('auth:api');

Route::post('/client', function (Request $request) {
    $data = $request->json()->all();
    return $data;
})->middleware('auth:api');

In the $data array i can see the accessToken.

在 $data 数组中,我可以看到 accessToken。

[user] => Array
  (
    [accessToken] => iOiJSUzI1NiIsImp0aSI6I...
  )

It send back HTTP 401 : Unauthorized

它发回 HTTP 401 : Unauthorized

Any help would be great. Thanks

任何帮助都会很棒。谢谢

回答by Gonzalo

Is your client able to send the access token in the header?

您的客户端是否能够在标头中发送访问令牌?

Authorization: Bearer <token>

If so, you can use the auth:apithat you already have in your code, here you can see how to call it with an example using Guzzle: https://laravel.com/docs/5.6/passport#protecting-routes

如果是这样,您可以使用auth:api您的代码中已有的,在这里您可以通过使用 Guzzle 的示例了解如何调用它:https://laravel.com/docs/5.6/passport#protecting-routes

$response = $client->request('GET', '/api/user', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer '.$accessToken,
    ],
]);

Otherwise, and against my advice because it's more standard and secure to use the heather Authorization, you may have two (not very appropriate) alternatives:

否则,与我的建议相反,因为使用 heather 授权更加标准和安全,您可能有两个(不是很合适的)替代方案:

  1. You can create a middleware to check if there is no Authorization in the heather, but in the body, and if so, move it to the heather before the auth:apimiddleware (but be sure to run this middleware first).
  2. Remove the auth:apimiddleware and authenticate either creating your own middleware or in the controller itself.
  1. 可以创建一个中间件来检查是否在heather中没有Authorization,而是在body中,如果有,则将其移动到auth:api中间件之前的heater中(但一定要先运行这个中间件)。
  2. 删除auth:api中间件并验证创建您自己的中间件或控制器本身。

Documentation about Laravel's middleware: https://laravel.com/docs/5.6/middleware

Laravel 中间件文档:https://laravel.com/docs/5.6/middleware

Here you can find more info about Laravel's out of the box authentication: https://laravel.com/docs/5.6/authentication

在这里您可以找到有关 Laravel 开箱即用身份验证的更多信息:https://laravel.com/docs/5.6/authentication

Note: Be sure that the documentation version and your Laravel's version match.

注意:确保文档版本和你的 Laravel 版本匹配。

More info about Barer Authentication: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

更多关于 Barer Authentication 的信息:https: //developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

This is an example (not tested) of how the middleware could work:

这是中间件如何工作的示例(未测试):

 <?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class BodyAuthenticate
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure                 $next
     * @param  string|null              $guard
     *
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (!Auth::guard($guard)->check()
            && null !== ($token = $request->json('access.user.accessToken', null))) {
            $request->headers->add([
                'Authorization' => 'Bearer ' . $token,
            ]);
        }

        return $next($request);
    }
}

You can also have a look at the Passport Middleware code here:

您还可以在此处查看 Passport Middleware 代码:

https://github.com/laravel/passport/blob/5.0/src/Http/Middleware/CreateFreshApiToken.php

https://github.com/laravel/passport/blob/5.0/src/Http/Middleware/CreateFreshApiToken.php

You have different ways to register your middleware:

您有不同的方式来注册您的中间件:

https://laravel.com/docs/5.6/middleware#registering-middleware

https://laravel.com/docs/5.6/middleware#registering-middleware

So you have to edit this file:

所以你必须编辑这个文件:

https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php

https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php

Depending on your API needs, you may do something like:

根据您的 API 需求,您可以执行以下操作:

protected $routeMiddleware = [
    ...

    'auth.body' => \App\Http\Middleware\BodyAuthenticate::class,
];

And then you can add this middleware in your route:

然后你可以在你的路由中添加这个中间件:

Route::post('/client', function (Request $request) {
    $data = $request->json()->all();
    return $data;
})->middleware('auth.body', 'auth:api');

Or make something more global (if all API calls require token auth) adding the middlewares to the api middleware group (in within App\Http\KernelClass too):

或者做一些更全局的事情(如果所有 API 调用都需要令牌认证)将中间件添加到 api 中间件组(也在App\Http\KernelClass 中):

'api' => [
    'throttle:60,1',
    'bindings',
    'auth.body',
    'auth:api',
],

Then, if the token sent match with any token in your database, the auth singleton will return the user who owns it. You can get that user like:

然后,如果发送的令牌与数据库中的任何令牌匹配,则身份验证单例将返回拥有它的用户。你可以让那个用户喜欢:

https://laravel.com/docs/5.6/authentication#retrieving-the-authenticated-user

https://laravel.com/docs/5.6/authentication#retrieving-the-authenticated-user

use Illuminate\Support\Facades\Auth;

// Get the currently authenticated user...
$user = Auth::user();

// Get the currently authenticated user's ID...
$id = Auth::id();

Keep in mind that the client has to send the token in every single call (is not a session).

请记住,客户端必须在每次调用(不是会话)中发送令牌。

So you can protect the routes:

所以你可以保护路由:

  1. As the doc suggest (in the route or the controller):
  1. 正如文档所建议的(在路由或控制器中):

https://laravel.com/docs/5.6/authentication#protecting-routes

https://laravel.com/docs/5.6/authentication#protecting-routes

Route::get('client', function () {
    // Only authenticated users may enter...
})->middleware('auth.body', 'auth:api');

Or in the controller:

或者在控制器中:

public function __construct()
{
    $this->middleware('auth.body', 'auth:api');
}
  1. With a group route:
  1. 使用团体路线:


    Route::middleware(['auth.body', 'auth:api'])->group(function () {
        Route::get('client', function () {
            // Uses first & second Middleware
        });

        Route::post('client', function (Request $request) {
            // Uses first & second Middleware
            $data = $request->json()->all();
            return $data;
        });

        Route::get('client/user/profile', function () {
            // Uses first & second Middleware
        });
    });

  1. If you edited App\Http\Kernelto add the middlewares globally (you don't need a group):
  1. 如果您编辑App\Http\Kernel以全局添加中间件(您不需要组):


    Route::get('client', function () {
        // Uses first & second Middleware
    });

    Route::post('client', function (Request $request) {
        // Uses first & second Middleware
        $data = $request->json()->all();
        return $data;
    });

    Route::get('client/user/profile', function () {
        // Uses first & second Middleware
    });

Tip: you can use the groups to add, not only middlewarebut also other interesting parameters such as controllers namespace, domain, naming alias prefix with as, or URI pathprefix.

提示:您可以使用组来添加,不仅middleware还包括其他重要的参数,如控制器namespacedomain,命名别名为前缀as或URIpath前缀。

Example:

例子:



    Route::group([
        'namespace'  => 'Client', // Loads from App\Http\Controllers\Client
        'domain'     => 'client.domain.com',
        'as'         => 'client::', // Check with `php artisan route:list --name=client`
        'middleware' => ['auth.body', 'auth:api'],
        'prefix'     => 'api',
    ], function () {
        // Uses first & second Middleware
        // GET https://client.domain.com/api/
        Route::get('/', function () {
            // ...
        });

        // Uses first & second Middleware
        // GET https://client.domain.com/api/profile
        Route::get('client/profile', function () {
            $user = Auth::user();
            // ...
        });

        // Uses first & second Middleware
        // POST https://client.domain.com/api/profile
        Route::post('client/profile', function (Request $request) {
            // ...
        });

        // Uses first & second Middleware
        // App\Http\Controllers\Client\PhotoController
        // @link: https://laravel.com/docs/5.6/controllers#resource-controllers
        // GET          /photos                 index   photos.index
        // GET          /photos/create          create  photos.create
        // POST         /photos                 store   photos.store
        // GET          /photos/{photo}         show    photos.show
        // GET          /photos/{photo}/edit    edit    photos.edit
        // PUT/PATCH    /photos/{photo}         update  photos.update
        // DELETE       /photos/{photo}         destroy photos.destroy
        Route::resource('photos', 'PhotoController');

        //...
    });

Notice that, if you edited App\Http\Kernelto add the middlewares globally, you don't need the middlewarein the group array.

请注意,如果您编辑App\Http\Kernel以全局添加中间件,则不需要middlewaregroup 数组中的 。

回答by LKirin

Thanks To Gonxalo and fwartner See:https://laracasts.com/discuss/channels/laravel/laravel-53-with-passport-get-current-user-with-personal-access-token

感谢 Gonxalo 和 fwartner 参见:https://laracasts.com/discuss/channels/laravel/laravel-53-with-passport-get-current-user-with-personal-access-token

If the Access Token is Not in your header then do what Gonxalo says above.

如果访问令牌不在您的标题中,则按照 Gonxalo 上面所说的进行操作。

Then add fwartner suggestion to get your user id.

然后添加 fwartner 建议以获取您的用户 ID。

The Alexa Skill doesn't send the accessToken in the header it send it in the body. I hope this helps someone down the road.

Alexa 技能不会在标题中发送 accessToken,而是在正文中发送它。我希望这可以帮助某人。

Here is my api.php:

这是我的 api.php:

<?php
use Illuminate\Http\Request;
/*
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:api');

Route::post('/alexa', function (Request $request) {

    $data = $request->json()->all();
    $jsonArray = json_decode(json_encode($data),true);

    $user = auth()->guard('api')->user();

    $userid =$user->id;
    $JsonOut = GetJsonResponse();
    return $JsonOut;
})->middleware('auth.body', 'auth:api');

function GetJsonResponse(){
    $NextNumber = 1;
    $EndSession  = "true";
    $SpeakPhrase = "Alexa Success.";


    $ReturnValue= '
    {
      "version": "1.0",
      "sessionAttributes": {
        "countActionList": {
          "read": true,
          "category": true,
          "currentTask": "none",
          "currentStep": '.$NextNumber.'
        }
      },
      "response": {
        "outputSpeech": {
          "type": "PlainText",
          "text": "' . $SpeakPhrase . '"
        },
        "reprompt": {
          "outputSpeech": {
            "type": "PlainText",
            "text": "Say next item to continue."
          }
        },
        "shouldEndSession": ' . $EndSession . '
      }
    }';
    return $ReturnValue;
}

Also, I added a header to the BodyAuthenticate.php middleware

另外,我在 BodyAuthenticate.php 中间件中添加了一个标头

$request->headers->add(['Accept' => 'application/json' ]); $request->headers->add(['Authorization' => 'Bearer ' . $token, ]);

$request->headers->add(['Accept' => 'application/json' ]); $request->headers->add(['Authorization' => 'Bearer' . $token, ]);