0

我正在使用我的 API 设置身份验证路由。我正在使用 laravel 5.5 和 tymondesigns/jwt-auth 1.0.0-rc.1 和 Postman 来与 API 交互。

身份验证路由/方法似乎有效:

/**
 * Authenticates a json request, generating a token.
 *
 * @param Request $request
 * @return JsonResponse
 */
public function authenticate(Request $request)
{
    // grab credentials from the request
    $credentials = $request->only('email', 'password');

    try {
        // attempt to verify the credentials and create a token for the user
        if (! $token = JWTAuth::attempt($credentials)) {
            return response()->json(
                [
                    'error' => 'Invalid credentials.',
                    'detail' => 'Please use your email and password to generate a token.'
                ],
                401);
        }
    } catch (JWTException $e) {
        // something went wrong whilst attempting to encode the token
        return response()->json(
            [
                'error' => 'Could not create token',
                'detail' => 'There was an internal problem and your token could not be created.'
            ], 500
        );
    }

    // all good so return the token
    return response()->json(compact('token'));
}

Postman API 发布请求返回(似乎是)有效响应,例如:

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4"
}

首先,出于基本测试目的,我将其提供给使用 GET 的操作,并带有以下后缀:

?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4

为了测试这一点,如果我执行以下操作:

public function globalObjects(Request $request): JsonResponse {
    var_dump(JWTAuth::parseToken()->authenticate(), JWTAuth::getToken()); exit;

   // ... later code that never gets reached
}

我得到以下信息:

bool(false) object(Tymon\JWTAuth\Token)#809 (1) { ["value":"Tymon\JWTAuth\Token":private]=> string(384) "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vc29sZGVyc3RhcmFwaS5jb20ubG9jYWwvYXBpL2F1dGhlbnRpY2F0ZSIsImlhdCI6MTUwNzg4NjU2OSwiZXhwIjoxNTA3ODkwMTY5LCJuYmYiOjE1MDc4ODY1NjksImp0aSI6IkpFWjBkc0dNbEVydXRHcFciLCJzdWIiOiIwNzk2MjhDMC03QjBDLTExRTYtODRERC1DQjAzMzVGN0JBNUQiLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Dl2EEaYZx3H5XXG9WUcPXYKuma0ZjCvcCsb99hgB6O4" }

..如:

  • 我收到令牌
  • 它没有找到用户

注意事项:

  • 我的主键是id,但它是一个 UUID,所以是二进制(16)......因此:
  • 我将标识符设置为:'identifier' => 'email'

以下请求:这里是\config\jwt.php

return [
    'secret' => env('JWT_SECRET', 'AqAWUTYISA56lrl2vcRtZQn4M4zk9onl'),
    'ttl' => 60,
    'refresh_ttl' => 20160,
    'algo' => 'HS256',
    'user' => 'App\User',
    'identifier' => 'email',
    'required_claims' => ['iss', 'iat', 'exp', 'nbf', 'sub', 'jti'],
    'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
    'providers' => [
        'user' => 'Tymon\JWTAuth\Providers\User\EloquentUserAdapter',
        'jwt' => 'Tymon\JWTAuth\Providers\JWT\Namshi',
        'auth' => 'Tymon\JWTAuth\Providers\Auth\Illuminate',
        'storage' => 'Tymon\JWTAuth\Providers\Storage\Illuminate',

    ],

];

谢谢

4

3 回答 3

2

这是我在 API 中使用的解决方案,效果非常好。

首先重写类Tymon\JWTAuth\Providers\Auth\Illuminate::class

<?php


namespace Scryba\Code\Laravel\Providers\Auth\Jwt;

use Tymon\JWTAuth\Contracts\Providers\Auth;
use Illuminate\Contracts\Auth\Guard as GuardContract;

class Illuminate implements Auth
{
/**
 * The authentication guard.
 *
 * @var \Illuminate\Contracts\Auth\Guard
 */
protected $auth;

/**
 * Constructor.
 *
 * @param  \Illuminate\Contracts\Auth\Guard  $auth
 *
 * @return void
 */
public function __construct(GuardContract $auth)
{
    $this->auth = $auth;
}

/**
 * Check a user's credentials.
 *
 * @param  array  $credentials
 *
 * @return bool
 */
public function byCredentials(array $credentials)
{
    return $this->auth->once($credentials);
}

/**
 * Authenticate a user via the id.
 *
 * @param  mixed  $id
 *
 * @return bool
 */
public function byId($id)
{
    //you can see i added hex2bin($id)because i save my UUID primary key as 
    //binary(16)
    return $this->auth->onceUsingId(hex2bin($id));
}

/**
 * Get the currently authenticated user.
 *
 * @return mixed
 */
public function user()
{
    return $this->auth->user();
}
}

然后将\config\jwt.php文件更新为

 'providers' => [

    /*
    |--------------------------------------------------------------------------
    | JWT Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to create and decode the tokens.
    |
    */

    'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,

    /*
    |--------------------------------------------------------------------------
    | Authentication Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to authenticate users.
    |
    */

    //'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
    'auth' => Scryba\Code\Laravel\Providers\Auth\Jwt\Illuminate::class,

    /*
    |--------------------------------------------------------------------------
    | Storage Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to store tokens in the blacklist.
    |
    */

    'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

],

在我的路线文件中

////// Protected methods (requires Authenticatication)
        $api->group(
            [
                'middleware' => ['api.auth'],
                'providers' => ['jwt'],

            ],function($api){

        $api->resource('cars', 'CarController', ['only' => [
            'index' ,'show'
        ]]);

        });

因此,在您的情况下,保留源文件 \vendor\tymon\jwt-auth\src\JWTAuth.php 原样,并在您的自定义类中编写如下代码(如果适用)。

/**
* Authenticate a user via the id.
*
* @param  mixed  $id
*
* @return bool
*/
public function byId($id)
{
   $id_text = $this->getPayload()->get('sub');

   $uuid_helper = new UuidHelper();
   $id = $uuid_helper->textIdToId($id_text);

  return $this->auth->onceUsingId($id);
}
于 2017-11-03T20:29:25.840 回答
0

您收到令牌但未正确解析,您需要检查令牌解析是否成功。

if (! $auth = JWTAuth::parseToken();) {
    throw Exception('JWTAuth unable to parse token from request');
}
dd(\Auth::id());

我建议你去你的 kernal.php 并在受保护的 $routeMiddleware 数组中添加以下行

'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',

然后转到您的路线并像中间件一样使用它来进行身份验证

 Route::group(['middleware' => 'jwt.auth'], function () {
  // Your routes here that you want to protect
        Route::get('foo', function () {
        return 'Hello World';
             });
     ]):

在此处输入图像描述

于 2017-10-18T15:40:27.423 回答
0

答案是:“如果不自行扩展,这与当前状态下的此功能不兼容”。

我希望这可以帮助其他使用 UUID 作为主键的人。如果不编辑供应商项目或扩展,您将无法做到这一点……但是,这是一个简单的解决方法。

我将与包作者一起提出这个问题,并希望找到一个更持久的解决方案。但是,这里有一个解决方法:

背景:

  • UUID 在数据库中存储为 binary(16)id列。
  • 这不是人类可读/文本友好的。
  • 为了解决这个问题,id_text字段作为自动生成的 mysql 字段存在
  • 注意 - 你永远不应该使用这些搜索(它严重地强调了数据库)
  • 这些是文本可读的,因此..可以很容易地用于表单等
  • 我创建了一个 UuidHelper 以便于翻译

JWT 中的问题:

  • 身份验证函数尝试将 id_text 解码为 id
  • 显然,这总是失败

在文件中\vendor\tymon\jwt-auth\src\JWTAuth.php

/**
 * Authenticate a user via a token.
 *
 * @return \Tymon\JWTAuth\Contracts\JWTSubject|false
 */
public function authenticate()
{
    $id_text = $this->getPayload()->get('sub');

    $uuid_helper = new UuidHelper();
    $id = $uuid_helper->textIdToId($id_text);

    if (! $this->auth->byId($id)) {
        return false;
    }

    return $this->user();
}

文档不是最清楚的,所以我认为'identifier' => 'email'会回避这个问题......结果不是。我会把这个反馈给作者

修改核心只是一个练习......我很确定这个类可以扩展,我很快就会尝试这个。在大多数情况下,编辑源当然不是最理想的。

但是 - 我希望这种挖掘能帮助人们理解这个问题。

于 2017-10-18T21:23:20.013 回答