新增一個 guard
config/auth.php
<?php
.
.
.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
'admin_user_api' => [
'driver' => 'passport',
'provider' => 'admin_users',
],
],
.
.
.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admin_users' => [
'driver' => 'eloquent',
'model' => App\Models\AdminUser::class,
],
.
.
.
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'admin_users' => [
'provider' => 'admin_users',
'table' => 'password_resets',
'expire' => 60,
],
],
];
?>
建立模型
/app/Models/AdminUser.php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
use DB;
class AdminUser extends Authenticatable
{
use HasApiTokens;
}
?>
建立 PassportCustomProvider
中介軟體
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Config;
class PassportCustomProvider
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$params = $request->all();
if (array_key_exists('provider', $params)) {
Config::set('auth.guards.api.provider', $params['provider']);
}
return $next($request);
}
}
?>
註冊路由中介軟體
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
.
.
.
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'passport-administrators' => \App\Http\Middleware\PassportCustomProvider::class,
];
.
.
.
?>
生成 passport
路由
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;
use Laravel\Passport\RouteRegistrar;
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(function (RouteRegistrar $router) {
$router->forAccessTokens();
}, ['prefix' => 'api/oauth', 'middleware' => 'passport-administrators']);
Passport::tokensExpireIn(now()->addDay(3));
Passport::refreshTokensExpireIn(now()->addDay(3));
}
}
?>
生成資料遷移檔案
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class OauthAccessTokenProviders extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('oauth_access_token_providers', function (Blueprint $table) {
$table->string('oauth_access_token_id', 100)->primary();
$table->string('provider');
$table->timestamps();
$table->foreign('oauth_access_token_id')
->references('id')->on('oauth_access_tokens')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('oauth_access_token_providers');
}
}
?>
新增一個事件監聽器
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
],
'Laravel\Passport\Events\AccessTokenCreated' => [
'App\Listeners\PassportAccessTokenCreated',
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
//
}
}
?>
<?php
namespace App\Listeners;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class PassportAccessTokenCreated
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param \Laravel\Passport\Events\AccessTokenCreated $event
* @return void
*/
public function handle(\Laravel\Passport\Events\AccessTokenCreated $event)
{
$provider = \Config::get('auth.guards.api.provider');
DB::table('oauth_access_token_providers')->insert([
"oauth_access_token_id" => $event->tokenId,
"provider" => $provider,
"created_at" => new Carbon(),
"updated_at" => new Carbon(),
]);
}
}
?>
新增一個全域性中介軟體來處理請求
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\DB;
use League\OAuth2\Server\ResourceServer;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
class PassportCustomProviderAccessToken
{
private $server;
public function __construct(ResourceServer $server)
{
$this->server = $server;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$psr = (new DiactorosFactory)->createRequest($request);
try {
$psr = $this->server->validateAuthenticatedRequest($psr);
$token_id = $psr->getAttribute('oauth_access_token_id');
if ($token_id) {
$access_token = DB::table('oauth_access_token_providers')->where('oauth_access_token_id',
$token_id)->first();
if ($access_token) {
\Config::set('auth.guards.api.provider', $access_token->provider);
}
}
} catch (\Exception $e) {
}
return $next($request);
}
}
?>
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\PassportCustomProviderAccessToken::class
];
.
.
.
?>
登入登出流程
<?php
Route::namespace('Api')->group(function () {
Route::post('login', 'LoginController@login');
Route::post('logout', 'LoginController@logout');
Route::post('refreshtoken', 'LoginController@refreshToken');
// 多表登入測試
Route::post('admin_user/login', 'LoginController@adminUserLogin');
Route::get('admin_user', 'AdminUsersController@index');
Route::post('admin_user/logout', 'LoginController@adminUserLogout');
});
?>
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Api\Traits\ProxyTrait;
use App\Models\AdminUser;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class LoginController extends ApiController
{
use AuthenticatesUsers, ProxyTrait;
public function __construct()
{
$this->middleware('guest')->except('logout,adminUserLogout,refreshToken');
}
.
.
.
public function adminUserLogin(Request $request)
{
$admin_user = AdminUser::where('email', $request->email)
->firstOrFail();
if (!Hash::check($request->password, $admin_user->password)) {
return $this->failed('密碼不正確');
}
$admin_user->last_login_at = Carbon::now();
$admin_user->save();
$tokens = $this->authenticate('admin_users');
return $this->success(['token' => $tokens, 'user' => $admin_user]);
}
public function adminUserLogout()
{
if (\Auth::guard('admin_user_api')->check()) {
// \Auth::guard('admin_user_api')->user()->token()->revoke();
\Auth::guard('admin_user_api')->user()->token()->delete();
}
.
.
.
?>
ProxyTrait
<?php
namespace App\Http\Controllers\Api\Traits;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
trait ProxyTrait
{
public function authenticate($guard = '')
{
$client = new Client();
try {
$url = request()->root() . '/api/oauth/token';
if ($guard) {
$params = array_merge(config('passport.proxy'), [
'username' => request('email'),
'password' => request('password'),
'provider' => $guard
]);
} else {
$params = array_merge(config('passport.proxy'), [
'username' => request('email'),
'password' => request('password'),
]);
}
$respond = $client->request('POST', $url, ['form_params' => $params]);
} catch (RequestException $exception) {
abort(401, '請求失敗,伺服器錯誤');
}
if ($respond->getStatusCode() !== 401) {
return json_decode($respond->getBody()->getContents(), true);
}
abort(401, '賬號或密碼錯誤');
}
public function getRefreshtoken()
{
$client = new Client();
try {
$url = request()->root() . '/api/oauth/token';
$params = array_merge(config('passport.refresh_token'), [
'refresh_token' => request('refresh_token'),
]);
$respond = $client->request('POST', $url, ['form_params' => $params]);
} catch (RequestException $exception) {
abort(401, '請求失敗,伺服器錯誤');
}
if ($respond->getStatusCode() !== 401) {
return json_decode($respond->getBody(), true);
}
abort(401, '不正確的 refresh_token');
}
}
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
class AdminUsersController extends AdminController
{
public function __construct()
{
parent::__construct();
$this->middleware('passport-administrators');
}
public function index(Request $request)
{
dd($request->user('admin_user_api'));
//dd(\Auth::guard('admin_user_api')->id());
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結