Laravel API 身份验证(Passport),从 post application/json 获取用户 ID

Posted

技术标签:

【中文标题】Laravel API 身份验证(Passport),从 post application/json 获取用户 ID【英文标题】:Laravel API Authentication (Passport), Get user ID from a post application/json 【发布时间】:2018-08-31 01:06:23 【问题描述】:

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

这是我的 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');

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

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

它发回 HTTP 401:未经授权

任何帮助都会很棒。谢谢

【问题讨论】:

我想我会像这样添加 accessToken: $jsonArray = json_decode(json_encode($data),true); $accesstoken = $jsonArray['session']['user']['accessToken']; $request->headers->set('Accept', 'application/json'); $request->headers->set('Authorization', 'Bearer'.$accesstoken);但是我将如何发送这个来获得所需的用户 ID? 【参考方案1】:

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

Authorization: Bearer <token>

如果是这样,您可以使用代码中已有的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,
    ],
]);

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

    您可以创建一个中间件来检查石南花中是否没有授权,但在正文中,如果有,请将其移至auth:api中间件之前的石南花(但请务必先运行此中间件)。 删除 auth:api 中间件并在创建您自己的中间件或在控制器本身中进行身份验证。

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

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

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

有关 Barer 身份验证的更多信息: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

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

 <?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);
    

您还可以在此处查看 Passport 中间件代码:

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

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

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

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

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

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

protected $routeMiddleware = [
    ...

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

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

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

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

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

然后,如果发送的令牌与数据库中的任何令牌匹配,则身份验证单例将返回拥有它的用户。您可以像这样获得该用户:

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();

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

这样你就可以保护路线了:

    按照文档的建议(在路由或控制器中):

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

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

或者在控制器中:

public function __construct()

    $this->middleware('auth.body', 'auth:api');

    团体路线:


    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
        );
    );

    如果您编辑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
    );

提示:您可以使用组来添加,不仅是middleware,还可以添加其他有趣的参数,例如控制器namespacedomain、使用as 命名别名前缀或URI path 前缀。

例子:



    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');

        //...
    );

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

【讨论】:

感谢您的回复。我的客户无法将访问令牌放在标头中。我有检查,标题中没有授权。 是否可以使用护照并将访问令牌发送给它?我是 laravel 和护照的新手,任何帮助都会很棒。 我编辑了响应,以便您了解中间件选项的工作方式。这对你有用吗? 我将 json 更改为“access.user.accessToken”。那我现在怎么称呼它?放回 auth:api?我应该怎么做我的路线? 我让您找到该部分的链接,因为这取决于您的项目需求,但我编辑了以下回复:1. json 更新为access.user.accessToken 2. 如何添加用于单个路由或作为 API 组的一部分的中间件。【参考方案2】:

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

如果访问令牌不在您的标头中,则执行 Gonxalo 上面所说的操作。

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

Alexa Skill 不会在标头中发送 accessToken,而是在正文中发送。我希望这对以后的人有所帮助。

这是我的 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;

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

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

【讨论】:

以上是关于Laravel API 身份验证(Passport),从 post application/json 获取用户 ID的主要内容,如果未能解决你的问题,请参考以下文章

php 使用Passport进行Laravel REST API身份验证:https://www.cloudways.com/blog/rest-api-laravel-passport-authen

Laravel API 身份验证(Passport),从 post application/json 获取用户 ID

Laravel 5.3 Passport API 在 Postman 中使用个人访问令牌未经身份验证

身份验证用户提供程序 [passport] 未使用 laravel 护照定义

使用 Passport 和 Laravel 进行身份验证时返回访问令牌和用户

Laravel 5.6 - Passport JWT httponly cookie SPA 身份验证用于自用 API?