使用 JWT 版本 (2018/09 更新)
前面幾個步驟同官方安裝教學
步驟說明
1. composer 載回來
composer require laravel/passport
2. 開資料表
php artisan migrate
然後你會多 5 張表 (主要使用到 oauth_access_token
)
3.創造 key
php artisan passport:install
他會幫你的 OAuth Server 準備一對 Key (storage/oauth-private.key, storage/outhpublic.key)
同時也準備 2 個 Client Key 在 oauth_clients
資料表內
Personal access client created successfully.
Client ID: 1
Client Secret: ETOhMRq7faRSnb1jN2F168jlbYFcf25MOHj0cOxt
Password grant client created successfully.
Client ID: 2
Client Secret: fibc50RiIjAiYSLR7xceQyoxQE3oGWtIXpCLj9Co
4. 附加 passport 至 auth 系統
- 在
app\User.php
新增Laravel\Passport\HasApiTokens
- line:5,11
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// ...
- 在
app/Providers/AuthServiceProvider.php
新增 passport 的 route (我們 jwt 版本可以不用) - line:29
<?php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
// set when access tokens expire
Passport::tokensExpireIn(now()->addDays(15));
}
}
- 在
config/auth.php
修改 guard 使用 passport
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
- 修改
app/Http/Kernel.php
加進 web middleware 中 (此步驟 JWT 才需要)
'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
5. 修改登入步驟
當我們登入成功的時候,回傳加密過的 jwt
在 app/Http/Controllers/Auth/LoginController.php
override 掉 authenticated function
當登入成功的時候會進入這個function
createToken 第一個參數是 token的名稱 第二個是權限領域(Scopes),建立後可以在oauth_xxx
資料表中確認
/**
* The user has been authenticated.
* Do not use the origin response of success login with 302, create access token
* and return json format
*
* @param Request $request
* @param User $user
* @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
* @throws \Illuminate\Validation\ValidationException
*/
protected function authenticated(Request $request, $user)
{
if (!is_null($user)) {
// create persionalAccessToken for authrizate API
$token = $user->createToken('access_token', ['guard', 'employee'])->accessToken ?: '';
return response()->json([
'access_token' => $token
], 200);
}
// throw error
return $this->sendFailedLoginResponse($request);
}
// 加入 scope middleware
// 在 app/Http/Kernel.php
裡面的 $routeMiddleware
scopes
是你指定的 scope 們都要通過 (AND)
scope
則是你指定的 scope 們其中之一通過 (OR)
可以挑需要用的(我是兩種都加進去了啦)
'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
- 回到
app/Providers/AuthServiceProvider.php
我們可以在這裡設定scpoe
們 - line:35
<?php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// set when access tokens expire
Passport::tokensExpireIn(now()->addDays(15));
// set when refresh tokens expire
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::tokensCan([
'admin' => 'system admin',
'guard' => 'a good guy',
'employee' => 'just a poor engineer'
]);
}
}
6. 裝備上去
在 routes/api.php
加上 middleware auth
並指定 guard 是 api
這樣有加上 middleware 的 API 們, 沒有 token 就進不去囉!
Route::apiResource('report', 'API\ReportController')
->middleware('auth:api')->middleware('scope:employee,guard');
Route::post('/report/multi_assign', 'API\ReportController@assignReports')
->middleware('auth:api')->middleware('scope:guard');
7. 前端接收
在這裡我將token存在local storage裡面
為了接收內容,所以將 make:auth產生的模板修改成 vue component 了
範例使用 ajax 做登入
axios.post('/login', {
'email': this.email,
'password': this.password
})
.then(res => {
window.localStorage.setItem('accessToken', res.data.access_token)
window.location.href = this.redirect_to
})
.catch(err => {
console.error('login failed')
// 處理回傳的錯誤訊息
})
在 resources/assets/js/bootstrap.js
為了不用每一次送 API 請求都要手動加上 token, 我們修改 axios 的預設
/**
* We will use laravel/passport JWT to verify API permission.
* Once user success to login, get a access token. The access token will be
* stored in the Local Storage of browser.
*/
let accessToken = JSON.parse(window.localStorage.getItem('accessToken')|| null);
if (accessToken) {
window.axios.defaults.headers.common['Authorization'] = accessToken;
}
- 補充
可以在app/Exceptions/Handler.php
做 error handle
在這裡把全部的 api error 都回傳401 未驗證
, 不良示範XDD
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'web':
$login = 'login';
break;
case 'api':
return response()->json(['error' => 'API Unauthenticated.'], 401);
break;
}
return redirect()->guest(route($login));
}
參考
Laravel 官方 Laravel Passport JWT Authentication
OAuth2
什麼是 OAuth?
例如說你從你的服務要跟 google 拿取使用者的資訊
- | - |
---|---|
Resource Owner | 使用者 |
Client | 你的服務 |
Authorization Server | 授權者,服務跟這邊拿token 如: google |
Resource Server | 服務會跟這裡拿資料 |
開始安裝 - 實戰時間
前幾個步驟同官方教學
1. composer 載回來
composer require laravel/passport
2. 開表
php artisan migrate
然後你會多 5 張表 (主要使用到 oauth_access_token
)
$ php artisan migrate
Migrating: 2016_06_01_000001_create_oauth_auth_codes_table
Migrated: 2016_06_01_000001_create_oauth_auth_codes_table
Migrating: 2016_06_01_000002_create_oauth_access_tokens_table
Migrated: 2016_06_01_000002_create_oauth_access_tokens_table
Migrating: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrated: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrated: 2016_06_01_000004_create_oauth_clients_table
Migrating: 2016_06_01_000005_create_oauth_personal_access_clients_table
Migrated: 2016_06_01_000005_create_oauth_personal_access_clients_table
3. 創造 key
php artisan passport:install
他會幫你的 OAuth Server 準備一對 Key (storage/oauth-private.key, storage/outhpublic.key)
同時也準備一組 Client Key 在 oauth_clients
資料表內
$ php artisan passport:install
Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 1
Client secret: VJZEYfTpsHBkNCv9ULUyHvGBbJvYiD1ZVP86cbYu
Password grant client created successfully.
Client ID: 2
Client secret: l4kh71C2DpdUsNmJFipi0hiDnhdgj6VfF5lGGDam
4. 附加 passport 至 auth 系統
- 在
app\User.php
新增一個 traitLaravel\Passport\HasApiTokens
- line:5,11
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// other code...
- 在
app/Providers/AuthServiceProvider.php
新增 passport 的 route - line:5 import passport
- line:29 add passport routes
<?php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
// set when access tokens expire
Passport::tokensExpireIn(now()->addDays(15));
}
}
- 在
config/auth.php
修改 guard 使用 passport
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],