Dingo + Laravel + JWT + Entrust + memcache 實現API設計
Dingo Api 是一個爲laravel設計的用於API開發的開源包,規範和簡化了Api的設計
JWT 即 Json Web Token,是一種新的用於API認證方式,區別於傳統的Session和Cookie方式,便於攜帶而且比較安全,因爲token只設計爲單次請求
Entrust 是一套基於角色的權限管理系統,用於分層系統設計
Memcache 是一個NoSQL存儲系統,使用鍵值對將數據存儲在內存中,實現快速訪問
DingoApi 安裝及使用
- 安裝
//項目基本目錄下執行
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"
- 配置
//配置可以卸載.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調試
- 認證方式
認證方式我們採用JWT方式,關於JWT可以自行谷歌,其他的配置請參考dingo/api 文檔
'auth' => [
'jwt' => 'Dingo\Api\Auth\Provider\JWT',
],
JWT認證方式
https://github.com/tymondesigns/jwt-auth
- 安裝
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
- 配置,請參考文檔,沒什麼好說的
- 創建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擴展庫安裝:
- 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 以系統進程運行,也就是作爲系統服務
- 安裝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
- 安裝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
- memadmin memcached監控工具
https://github.com/junstor/memadmin
需要PHPmemcache擴展