最近在學習前后端分離開發,發現 在laravel中實現前后台分離是無法無法使用 CSRF Token 認證的。因為 web 請求的用戶認證是通過Session和客戶端Cookie的實現的,而前后端分離的應用無法通過API請求將Cookie 和 CSRF Token 從前端傳遞到后端,但是還有一種解決方法,就是使用laravel自帶的 API token認證。
第一步:用戶表添加api_token字段
1、可以通過數據遷移的方式添加,像這樣:
php artisan make:migration --table=用戶表名 add_api_token
然后編寫這個遷移文件,文件位於 database/migration 中
class AddApiToken extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('用戶表名', function (Blueprint $table) {
$table->string('api_token', 200)->unique()->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('用戶表名', function (Blueprint $table) {
$table->dropColumn(['api_token']);
});
}
}
然后執行遷移命令
php artisan migrate
2、或者像我這樣,直接在數據庫用戶表中添加,O(∩_∩)O哈哈~
因為 varchar 存儲的是變長數據,也就是數據的真實長度,所以不要吝嗇可以給長度設大點。
第二步、添加認證服務方
我是多表認證,每個用戶角色有一張表,所以需要添加認證服務方,在 config/auth.php 中添加。一般使用已經默認的 api 認證方就好,
第三步、給用戶模型添加生成api_token方法
/**
* 更新token
* @return mixed|string
*/
public function generateToken() {
$this->api_token = str_random(128);
$this->save();
return $this->api_token;
}
第四步、在控制器中添加登錄方法
這是我的登錄認證,是基於多表的用戶認證,我是個小菜菜,細節就不給你們看了,怕你們噴我⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄。總之是在登陸驗證成功之后,生成api_token並返回就可以了。
第五步、給路由添加認證中間件
在 api.php 添加如下路由,login 不需要守衛,給 logout 和 其他需要認證的路由添加守衛就可以了(auth:admin , 對應上面的admin用戶)
Route::any('unAuth', function () {
return responseToJson(1,'未認證或認證失敗');
})->name('unAuth');
Route::prefix('admin')->namespace('Admin')->group(function() {
Route::post('login', 'LoginController@login');
Route::middleware('auth:admin')->group(function() {
Route::post('logout', 'LoginController@logout');
Route::get('getMenu', 'MenuController@getMenu');
});
});
使用的是auth中間件,默認的路由我沒有O(∩_∩)O,所以需要進行修改。
修改中間件 Authenticate.php , 位於 app/Http/Middleware/Authenticate.php 。
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('unAuth');
}
}
}
現在就已經好了,在登陸之后會返回 api_token ,然后請求其他路由的時候把 api_token 當參數傳過來。這樣當請求需要認證的路由的時候如果沒有 api_token 或者 api_token 錯誤,就會跳轉到 unAuth 路由,然后返回定義好的提示信息。
第六步、退出時清除 token
public function logout()
{
$user = Auth::guard('admin')->user();
if ($user) {
$user->api_token = null;
$user->save();
}
return responseToJson(0,'退出成功');
}
還可以寫個中間件,每隔一段時間更新一下 api_token 值,同時前端也要更新 api_token 。我寫的也不是多好,可以看一下
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard)
{
$response = $next($request);
//驗證token是否過期
$user = Auth::guard($guard)->user();
if (isTimeGreater($user->updated_token_at)){
$response->header("api_token", $user->generateToken());
}
return $response;
}