JWT One More Look
打赏作者

ogre222

我把Users表中id字段改成uid,登录可以获取token值,但

$api->group(['middleware' => 'jwt.auth'],function($api){
            $api->get('users','UsersController@index');
            $api->get('users/{uid}','UsersController@show');
 }); 
$api->get('me','AuthController@getAuthenticatedUser');

都获取为

[
"user_not_found"
]

这个是什么原因啊?@JellyBool

JellyBool

你在User.php中加一个:

protected $primaryKey='uid';

这样试试? @ogre222

ogre222

Thank you 我得周一才能试一下,如果有问题,还得向你请教了。@JellyBool

JellyBool

没事,有问题就问 @ogre222

manpai

验证里面的name 怎么对应其它的字段 我想改为mobile字段

$credentials = [
            'name' => $request->get('mobile'),
            'password' => $request->get('password'),
        ];

我使用

public function getAuthName()
    {
        return $this->mobile;
    }

不能使其对应

JellyBool 回复 manpai

app/Http/AuthController.php中指定:

protected $username = 'mobile';

getAuthName不用的话,试试

lg23 回复 JellyBool

登录正常,token 获取正常 但访问 user/me 路由(控制器: getAuthenticatedUser)时提示:
“user_not_found” 或 token_invalid
尝试过在 app\http\AuthController.php 中指定 protected $username = ‘mobile’;
在 user.php 中添加 public function getAuthName() 但问题依旧存在
控制器代码

<?php
namespace App\Api\Controllers\V1;

use Illuminate\Http\Request;
use App\Api\Controllers\BaseController;
use Tymon\JWTAuth\Exceptions\JWTException;
use JWTAuth;
use App\Service\UserService;
use Carbon\Carbon;

class AuthController extends BaseController
{
     private static $userService;
     protected $username = 'tel';

     public function __construct(UserService $userService)
     {
         self::$userService = $userService;
     }

    /**
     * 验证用户  获取token
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function authenticate(Request $request)
    {
        $payload = [
            'tel' => $request->get('phone'),
            'password' => $request->get('passw'),
            'status' => 0
        ];

        try {
            // attempt 尝试验证凭据并为用户创建令牌
            if (! $token = JWTAuth::attempt($payload)) {
                // 返回无效令牌
                return response()->json(['error' => 'invalid_credentials'], 401);
              }
        } catch (JWTException $e) {
            // 尝试创建 token 令牌时出错
            return response()->json(['error' => 'could_not_create_token'], 500);
        }

        $result['data'] = [
            'token' => $token,
            'expired_at' => Carbon::now()->addMinutes(config('jwt.ttl'))->toDateTimeString(),
            'refresh_expired_at' => Carbon::now()->addMinutes(config('jwt.refresh_ttl'))->toDateTimeString(),
            'type' => true,
        ];

        return $this->response->array($result)->setStatusCode(201);
        
    }


    /**
     * 根据 token 获取用户信息
     * 
     */
    public function getAuthenticatedUser()
    {
       try {// parseToken 解析令牌请求来源
           if (! $user = JWTAuth::parseToken()->authenticate()) {
               return response()->json(['user_not_found'], 404);
           }
       } catch (TokenExpiredException $e) {
           return response()->json(['token_expired'], $e->getStatusCode());
       } catch (TokenInvalidException $e) {
           return response()->json(['token_invalid'], $e->getStatusCode());
       } catch (JWTException $e) {
           return response()->json(['token_absent'], $e->getStatusCode());
       }

       // token 有效,找到用户
       return response()->json(compact('user'));
    }

}

路由代码:
$api = app('Dingo\Api\Routing\Router');

$api->version('v1', function ($api) {
    $api->group(['namespace' => 'App\Api\Controllers\V1', 'middleware' => 'cors'], function ($api) {

        $api->POST('/register', [
            'limit' => 50, 
            'expires' => 5,
            'as' => 'register.register',
            'uses' => 'AuthController@register',
        ]);
        // 登录
        $api->POST('/login', [
            'limit' => 50, 
            'expires' => 5,
            'as' => 'login.authenticate',
            'uses' => 'AuthController@authenticate',
        ]);

        // 通过 jwt.auth 中间件限制未登录权限
        $api->group(['middleware' => 'jwt.refresh'], function ($api) {
            $api->get('user/me', 'AuthController@getAuthenticatedUser');

        });

    });
    
})

user.php 代码 
<?php
namespace App\Model;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{   
    // JWT 中有指定验证的字段,使用 Notifiable 来修改这些指定
    use Notifiable;
    
    /**
     * 白名单 $fillable 属性指定了哪些字段支持批量赋值
     * @var array
     */
    protected $fillable = ['uid', 'username', 'tel', 'password', 'pic', 'status', 'addtime'];
    /**
     * 模型所使用的数据库表
     * @var string
     */
    protected $table = 'data_users';
    /** 
     * 自定义主键
     */
    protected $primaryKey = 'uid';

    /**
     * 关闭 递增
     */
    public $incrementing = false;
    /**
     * 关闭 创建时间 与 更新时间的自动维护
     */
    public $timestamps = false;

    /** 
     * 转换成数组或 JSON 时隐藏属性
     * 查询用户的时候,不暴露密码
     * @var array 
     */  
    protected $hidden = ['password', 'remember_token'];

    /**
     * jwt 默认密码字段 password 
     * 修改密码字段
     */
    public function getAuthPassword()
    {
        return $this->password;
    }

    /**
     * 修改 jwt 默认用户名字段 
     */
    public function getAuthName()
    {
        return $this->tel;
    }

}

JellyBool 回复 lg23

可能是由这个引起的:

protected $primaryKey = 'uid';
lg23 回复 JellyBool

我忘了当时是什么情况,大概记得是sql出错,说是到不到 id,因为我表中没有id,所以在user.php里设置了自定义主键,晚点回来,我试一下。谢谢群主

lg23 回复 JellyBool

Column not found: 1054 Unknown column ‘data_users.id’ in ‘where clause’ (SQL: select * from data_users where data_users.id is null limit 1)"

对了,上次就是有这个报错,我才使用了自定义主键 protected $primaryKey = ‘uid’;
如果不使用自定义主键,这里会报上面的错,使用可能找不到用户,那我应该怎么处理呢?

lg23 回复 JellyBool

问题我解决了,我在数据库中增加了一个 id 字段,这个问题让我纠结了好几天,谢谢了

天山网艾克

为什么用bingo 之后 显示 的json 只有data 其他的 状态码,状态消息, 等那些东西没有吗 ?

jasester

我把email和password 改成 user_phone和 user+password 也是按照你的方法修改的 但是登录的时候还是提示

{
  "error": "invalid_credentials"
}
shadow610 回复 jasester

总结一下:
1.users表要改表结构,字段名’email’改为’user_email’,字段名’password’改为’user_password’
2.AuthController中添加

$credentials = [
			'user_email' => $request->get('user_email'),
			'password' => $request->get('user_password')
		];

这里需要注意数组的键为password,而不是user_password
3.User的model里,添加

public function getAuthPassword()
	{
		return $this->user_password;
	}

4.Postman的表单提交body里,分别改为’user_email’和’user_password’

shadow610 回复 jasester
//总结一下:
//1.users表要改表结构,字段名'email'改为'user_email',字段名'password'改为'user_password'
//2.AuthController中添加
$credentials = [
            'user_email' => $request->get('user_email'),
            'password' => $request->get('user_password')
        ];
//这里需要注意数组的键为password,而不是user_password
//3.User的model里,添加
public function getAuthPassword()
    {
        return $this->user_password;
    }
//4.Postman的表单提交body里,分别改为'user_email'和'user_password'
shadow610
$credentials = [
			'user_email' => $request->get('user_email'),
			'password' => $request->get('user_password')
		];

数组这里是password,而不是user_password,各位需要注意一下

bii

想问一下,如何用其它的用户模型验证,不用user模型可以吗?或者多个模型验证

JellyBool 回复 bii

多模型应用 jwt 可能就不是 jwt 的应用场景了。但是一定要实现的话,就是在 5.2 的多表认证基础上直接基本上就可以使用了:

https://laravist.com/series/what-is-new-in-laravel-5-2-series/episodes/6

bii 回复 JellyBool

可是写API的时候需要用JWT啊,前后台都用ajax请求调用的接口,有什么好办法么?

JellyBool 回复 bii

所以你去实现一下多表认证的配置,应该就可以使用 jwt 了。

你的用户都是分表的么?

lg23

public function getAuthPassword() {
}
为什么只有一个修改密码的字段,没有修改用户名(email)的。另外,这个方法什么位置调用???

JellyBool 回复 lg23

你找一下这个 trait Illuminate\Auth\Authenticatable。

修改用户名的话,你在 AuthController 里面声明一下 public $username = ‘username’;

lg23

在 use Dingo\Api\Routing\Helpers; 这个里面有一个方法

/**
     * Get the authenticated user.
     * 获取认证用户
     * @return mixed
     */
    protected function user()
    {
        return app(Auth::class)->user();
    }

我想调用这个方法应该如何调用呢?
我目前的调用方式
创建基础控制器

<?php
namespace App\Api\Controllers;

use Dingo\Api\Routing\Helpers;
use App\Http\Controllers\Controller;

class BaseController extends Controller
{
	// 接口帮助调用
	use Helpers;
}

其它控制器继承基础控制器

<?php
namespace App\Api\Controllers\V1;

use App\Api\Controllers\BaseController;
use Illuminate\Http\Request;
use App\Service\OrderService;
use App\Api\Transformers\OrderTransformer;
use App\Api\Controllers\V1\AuthController;


class OrderController extends BaseController
{
    public function show(Request $request, $type)
    {   
        $user = $this->user();
        return $user;
        $order = self::$orderService
                     ->apiGetOrderList($uid, $type);

        // 不存在 调用dingo 的 response 方法返回错误信息
        if(!$order) {
            return $this->response->errorNotFound('order not found');
        }

        return $this->response->item($order, new OrderTransformer());
    }

}

在上面的调用过程中,出现以下报错:
“message”: “Call to undefined method Closure::authenticate()”,
“status_code”: 500,
“debug”: {
“line”: 82,
“file”: “/vagrant/tb100/admin/vendor/dingo/api/src/Auth/Auth.php”,
“class”: “Symfony\Component\Debug\Exception\FatalThrowableError”,

初步猜测是同 Auth 有关,这里具体应该如何配置,还请求指点!

JellyBool 回复 lg23

那是一个 trait ,你只要 use 就可以用了啊。

之前也说过吧,先看看这个 ?https://www.laravist.com/learn/laravel

个人觉得你的 OOP 基础基本没有

lg23 回复 JellyBool
<?php
namespace App\Api\Controllers\V1;

use App\Api\Controllers\BaseController;
use Illuminate\Http\Request;
use App\Service\OrderService;
use App\Api\Transformers\OrderTransformer;
use App\Api\Controllers\V1\AuthController;
use Dingo\Api\Routing\Helpers;

class OrderController extends BaseController
{
    use Helpers;
    public function show(Request $request, $type)
    {   
        $user = $this->user();
        return $user;
        $order = self::$orderService
                     ->apiGetOrderList($uid, $type);

        // 不存在 调用dingo 的 response 方法返回错误信息
        if(!$order) {
            return $this->response->errorNotFound('order not found');
        }

        return $this->response->item($order, new OrderTransformer());
    }

}

我在这里 use 后,还是报错

"message": "Call to undefined method Closure::authenticate()",
  "status_code": 500,
  "debug": {
    "line": 82,
    "file": "/vagrant/tb100/admin/vendor/dingo/api/src/Auth/Auth.php",
    "class": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",

我不知道为什么这个方法是正常调用的,我先用这个方法
$user = JWTAuth::parseToken()->authenticate();

XBisATrouble

jwt默认找的好像是App下面的User model,如果我现在想把User这个model移动到App\Model下,该怎么修改命名空间

JellyBool 回复 XBisATrouble

你改一下 auth 的配置文件或者是指 jwt 的配置中,model 的配置

XBisATrouble

请问我的token会过期,那app调用这个接口的时候难道还要重新登陆吗?有什么解决方案?

JellyBool 回复 XBisATrouble

貌似是你添加 refresh.token 这个 middleware 就好了,每次都会 refresh

beaplat-61f

上节视频的middleware是jwt.auth,这一节就变成jwt.refresh了

X氵丿米丨

怎么使用JWT配置多用户认证?比如members、staffs