您的位置:首页 > 编程语言 > PHP开发

Laravel5.2+Dingo/API+JWTauth的想着问题

2016-12-06 14:34 781 查看
JWTAuth 默认使用 Users 表做为登录认证的表。而我的需求比较奇葩,共有两个不同的表;除此之外,还需要对 JWTAuth 的错误进行自定义。在搜索无果后,只好自己动手实现这两个需求。

首先解决第二个问题,对 JWTAuth 进行错误自定义。这种情况下,我们可以自己去添加一个中间件处理身份认证。

添加中间件处理身份验证

1、添加一个 Middleware

可以使用命令行添加:

1
php artisan make:middleware GetUserFromToken
此命令将会在
app/Http/Middleware
目录内置立一个名称为
GetUserFromToken
的类。

2、在
GetUserFromToken
中编辑代码,这里仿照 JWTAuth 写了
Middleware


12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
<?phpnamespace App\Http\Middleware;use Closure;use JWTAuth;use Tymon\JWTAuth\Exceptions\JWTException;use Tymon\JWTAuth\Exceptions\TokenExpiredException;use Tymon\JWTAuth\Exceptions\TokenInvalidException;class GetUserFromToken{    public function handle($request, Closure $next)    {        $auth = JWTAuth::parseToken();        if (! $token = $auth->setRequest($request)->getToken()) {            return response()->json([                'code' => '',                'message' => 'token_not_provided',                'data' => '',            ]);        }                try {            $user = $auth->authenticate($token);        } catch (TokenExpiredException $e) {            return response()->json([                'code' => '',                'message' => 'token_expired',                'data' => '',            ]);        } catch (JWTException $e) {            return response()->json([                'code' => '',                'message' => 'token_invalid',                'data' => '',            ]);        }        if (! $user) {            return response()->json([                'code' => '',                'message' => 'user_not_found',                'data' => '',            ]);        }        //$this->events->fire('tymon.jwt.valid', $user);        return $next($request);    }}
我将每次错误返回数据替换成自己设置的错误信息。

3、在
/app/Http/Kernel.php
$routeMiddleware
新增如下内容:

1234
protected $routeMiddleware = [    ...    'jwt.api.auth' => \App\Http\Middleware\GetUserFromToken::class, //新增注册的中间件];
4、在路由中指定使用
jwt.api.auth


1
['middleware' => 'jwt.api.auth']
完成上面的操作,我们新增处理接口身份认证中间件就完成了。

现在需要处理前一个问题。

多表配置

在 JWTAuth 中,可以在配置文件 jwt.php 中设置
Us
e2b8
er Model namespace
,所以可以在
Middleware
handle
部分添加如下代码来动态配置
User Model namespace


1
config(['jwt.user' => 'App\Models\User']);
这里,我把 User 表放到了
App\Models\
中和其他的统一进行管理。不过我在测试中一直出现
App\User
未定义错误。然后就开始了漫长的定位之旅。首先在访问
authenticate
得到

12345678910
public function authenticate($token = false){    $id = $this->getPayload($token)->get('sub');    if (! $this->auth->byId($id)) {        return false;    }    return $this->auth->user();}
然后,在
Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter
中找到
byId
user
对应代码如下

123456789
public function byId($id){    return $this->auth->onceUsingId($id);}public function user(){    return $this->auth->user();}
经过测试发现 auth 实际上是一个
Illuminate\Auth\SessionGuard
实例,然后在其中发现了
onceUsingId
user
部分代码

12345678910
public function onceUsingId($id){    if (! is_null($user = $this->provider->retrieveById($id))) {        $this->setUser($user);        return true;    }    return false;}
在查找
provider
所在位置时定位到文件
Illuminate\Auth\CreatesUserProviders.php
中找到如下代码

123456789101112131415161718
public function createUserProvider($provider){    $config = $this->app['config']['auth.providers.'.$provider];    if (isset($this->customProviderCreators[$config['driver']])) {        return call_user_func(            $this->customProviderCreators[$config['driver']], $this->app, $config        );    }    switch ($config['driver']) {        case 'database':            return $this->createDatabaseProvider($config);        case 'eloquent':            return $this->createEloquentProvider($config);        default:            throw new InvalidArgumentException("Authentication user provider [{$config['driver']}] is not defined.");    }}
这里通过
auth.providers.users
配置设置
$config
,而
auth.providers.users
在文件 auth.php 中默认配置如下

123456
'providers' => [    'users' => [        'driver' => 'eloquent',        'model' => App\User::class,    ],]
所以程序走到了
return $this->createEloquentProvider($config);
这一步,继续跟踪得到:

1234
protected function createEloquentProvider($config){    return new EloquentUserProvider($this->app['hash'], $config['model']);}
其中
$config['model']
则就是原型:

12345
public function __construct(HasherContract $hasher, $model){    $this->model = $model;    $this->hasher = $hasher;}
到此,确定了
model
所在位置,只需要在
Middleware
中添加如下配置

1
config(['auth.providers.users.model' => \App\Models\User::class]);
最终代码如下

1234567891011121314151617181920212223242526272829303132333435363738
config(['jwt.user' => '\App\Models\User']);config(['auth.providers.users.model' => \App\Models\User::class]);$auth = JWTAuth::parseToken();if (! $token = $auth->setRequest($request)->getToken()) {    return response()->json([        'code' => '',        'message' => 'token_not_provided',        'data' => '',    ]);}try {    $user = $auth->authenticate($token);} catch (TokenExpiredException $e) {    return response()->json([        'code' => '',        'message' => 'token_expired',        'data' => '',    ]);} catch (JWTException $e) {    return response()->json([        'code' => '',        'message' => 'token_invalid',        'data' => '',    ]);}if (! $user) {    return response()->json([        'code' => '',        'message' => 'user_not_found',        'data' => '',    ]);}//$this->events->fire('tymon.jwt.valid', $user);return $next($request);
到这里为止,实现了自定义表名功能,在结合自定义
Middleware
部分,就可以实现多表认证。只需要对每一种认证都实现对应的
Middleware
,在接口处分别对不同接口使用不同的
Middleware
进行验证就好。

当然,这样的实现肯定不完美,因为所有的事件部分代码全部删除了。这部分还没有想到什么好的解决办法,自己实现 event 应该是可行的,这里就么有尝试。

转至:http://www.hashcoding.net/2016/04/28/Laravel5-2-Dingo-API-JWTauth-%E7%9A%84%E5%9D%91/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: