Dingo + Laravel + JWT + Entrust + memcache 实现API设计

时间:2022-04-09 20:39:01

Dingo + Laravel + JWT + Entrust + memcache 实现API设计

Dingo Api 是一个为laravel设计的用于API开发的开源包,规范和简化了Api的设计

JWT 即 Json Web Token,是一种新的用于API认证方式,区别于传统的Session和Cookie方式,便于携带而且比较安全,因为token只设计为单次请求

Entrust 是一套基于角色的权限管理系统,用于分层系统设计

Memcache 是一个NoSQL存储系统,使用键值对将数据存储在内存中,实现快速访问

DingoApi 安装及使用

https://github.com/dingo/api

  1. 安装
//项目基本目录下执行
composer require dingo/api:1.0.x@dev
//config/app.php
'providers' => [
Dingo\Api\Provider\LaravelServiceProvider::class
]
//发布配置文件
php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"
  1. 配置
//配置可以卸载.env文件中或者config/api.php
API_STANDARDS_TREE=vnd //api 标准
API_SUBTYPE=myapp //项目短名称
API_PREFIX=api
API_DOMAIN=api.myapp.com //这里记住API_PREFIX或者API_DOMAIN通知只能配置一个,或的关系,访问的时候通过 http://127.0.0.1:8000/api/your_route 或者 http://api.myapp.com/your_route
API_VERSION=v1
API_NAME="My API" //在.env文件中一定要注意不能有多余的空格,负责出现莫名的错误,如果写成API_NAME=My API就会出错
API_CONDITIONAL_REQUEST=false
API_STRICT=false //如果配置为真,将需要在每次访问api是添加Accept头:application/vnd.myapp.v1+json
API_DEFAULT_FORMAT=json //api返回格式
API_DEBUG=true //API调试
  1. 认证方式

认证方式我们采用JWT方式,关于JWT可以自行谷歌,其他的配置请参考dingo/api 文档

'auth' => [
'jwt' => 'Dingo\Api\Auth\Provider\JWT',
],

JWT认证方式

https://github.com/tymondesigns/jwt-auth

  1. 安装
composer require "tymon/jwt-auth:0.5.*"
//添加服务
'Tymon\JWTAuth\Providers\JWTAuthServiceProvider'
//添加alias
JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth'
//发布配置文件
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
//生成jwt:key
php artisan jwt:generate
  1. 配置,请参考文档,没什么好说的
  2. 创建token

token可以基于任何传入的数据创建,不过我们一般使用从用户创建token,如:

$user = User::first();

$token = JWTAuth::fromUser($user);

这里具体的流程是,用户提交认证数据,然后根据提交数据查询用户,得到用户以后创建token,这里贴一段我的代码

public function signIn(Request $request)
{

$info = (new SignInForm())->load($request, 'sign-in');
if($info instanceof Response)
{
return $info;
}

$user = null;

if(Auth::attempt(['nick_name' => $request->input('identity'), 'password' => $request->input('password'), 'status' => User::STATUS_NORMAL])
|| Auth::attempt(['email' => $request->input('identity'), 'password' => $request->input('password'), 'status' => User::STATUS_NORMAL])
|| Auth::attempt(['mobile' => $request->input('identity'), 'password' => $request->input('password'), 'status' => User::STATUS_NORMAL] ))
{
$user = Auth::user();
}

if($user)
{
$token = JWTAuth::fromUser($user);
} else {
return ApiResponse::apiResponse(ResponseCode::SIGN_IN_FAILED);
}

return ApiResponse::apiResponse(ResponseCode::SIGN_IN_OK, [
'token' => $token
], 0);
}

客户端在收到token以后,在需要认证api中加入Authorization头: Authorization:Bearer {token},我们在dingo/api中配值了API使用jwt认证,所以我们在我们的路由中添加jwt中间件:

//routes.php
<?php

//这里使用的web组中间件中,我只是开启了session,其他的都已经注释掉了,尤其是CSRF中间件应该去掉,否则每次还要提交CSRF值,也可以单独设置session
// 'web' => [
// //\App\Http\Middleware\EncryptCookies::class,
// //\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// \Illuminate\Session\Middleware\StartSession::class,
// //\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// //\App\Http\Middleware\VerifyCsrfToken::class,
// ],

$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api){

$api->group(['namespace' => 'App\Http\Controllers\V1', 'middleware' => ['web']], function ($api){

$api->post('sign-up', ['as' => 'user.signUp', 'uses' => 'AppController@signUp']);
$api->post('sign-in', ['as' => 'user.signIn', 'uses' => 'AppController@signIn']);
$api->post('third-auth', ['as' => 'user.thirdAuth', 'uses' => 'AppController@thirdAuth']);
$api->post('password-reset/send-verify-code', 'PasswordController@sendResetPasswordEmail');
$api->post('password-reset/set-new-password', 'PasswordController@resetNewPassword');

$api->group(['middleware' => 'api.auth'], function ($api){

$api->group(['middleware' => ['before' => 'jwt.auth']], function ($api){

$api->group(['middleware' => ['after' => 'jwt.refresh']], function ($api){

//用户资源
$api->resource('user', 'UserController', [
'only' => ['show', ],
'names' => [
'show' => 'user.show',
],
]);

//用户资料资源
$api->resource('profile', 'ProfileController', [
'only' => ['show', ],
'names' => [
'show' => 'profile.show'
],
]);

});

$api->get('logout', ['as' => 'user.logout', 'uses' => 'AppController@logout']);
$api->get('refresh-token', ['as' => 'user.refreshToken', 'uses' => 'AppController@refreshToken']);
});
});

});
});

api.auth中间件不要配置,只是说明路由是保护路由;

jwt.auth 需要配置,配置请看文档,会在api请求处理之前检查用户是否已经认证,主要是验证Authorization头部信息;

jwt.refresh 会在访问成功之后,刷新token,并附加在响应头部的Authorization头部中;但是这个中间件应该只能用于需连续访问的API中,像logout和refresh-token就不需要刷新。
说到刷新token,如果大家了解jwt认证机制,应该明白token只能用于单次请求,请求成功之后失效,不过可以通过这个旧的token刷新得到新的token;
因此这里要启用黑名单功能,将失效的token写入黑名单。黑名单十一缓存的形式存在,根据应用缓存的配置,写入文件或者数据库或者其他形式,如果是写入文件,你的storage目录应该要具有可写权限;

需要提醒的是缓存形式配置为file时,entrust不能正常使用,此问题需等待新版本修复。折中的办法是你可以将缓存设置memcached,就不会出现问题了

entrust

https://github.com/Zizaco/entrust

关于entrust本人觉得除了缓存配置比较坑意外,其他应该都能看得懂,有问题请留言

ubuntu memcached 服务器以及PHP扩展库安装:

  1. memcached 服务器安装
//方法一:
sudo apt-get install memcached
//方法二(编译安装):
wget http://memcached.org/files/memcached-1.4.25.tar.gz
tar xzvf memcached-1.4.25.tar.gz
cd memcached-1.4.25
./configure && make && make test && sudo make install
//最后测试
memcached -d -m 50 -p 11211 -u root
-m 指定使用多少兆的缓存空间;-p 指定要监听的端口; -u 指定以哪个用户来运行 -d 以系统进程运行,也就是作为系统服务
  1. 安装libmmecached
wget https://launchpad.net/libmemcached/1.0/0.51/+download/libmemcached-0.51.tar.gz
tar xzvf libmemcached-0.51.tar.gz
cd libmemcached-0.51
./configure --prefix=/usr/local/libmemcached --with-memcached
sudo make && sudo make install
  1. 安装memcached扩展库
//安装之前可能要求安装pkg-config
sudo apt-get install phk-config
wget http://pecl.php.net/get/memcached-2.2.0.tgz
tar xzvf memcached-2.2.0.tgz
cd memcached-2.2.0
phpize5
/configure --with-php-config=/usr/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached --enable-memcached --disable-memcached-sasl
sudo make && sudo make install
  1. memadmin memcached监控工具
    https://github.com/junstor/memadmin

需要PHPmemcache扩展