oracle access manager token,Laravel 自带的 API 守卫驱动 token 使用详解
在Laravel框架中,默認(rèn)的用戶認(rèn)證守衛(wèi)有兩個(gè),web和api,web守衛(wèi)默認(rèn)的驅(qū)動(dòng)是session,而api守衛(wèi)默認(rèn)的驅(qū)動(dòng)是token。那么,該如何使用這個(gè)token驅(qū)動(dòng)?
尋找 TokenGuard
通過 Auth::guard() 這個(gè)方法,可以追溯到 token 驅(qū)動(dòng)對(duì)應(yīng)的類。來看Illuminate\Auth\AuthManager中的代碼:
/**
* Attempt to get the guard from the local cache.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
*/
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}
/**
* Resolve the given guard.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
}
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
}
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
}
throw new InvalidArgumentException("Auth driver [{$config['driver']}] for guard [{$name}] is not defined.");
}
可以看到,默認(rèn)情況下就會(huì)調(diào)用到 createTokenDriver 。來看看這個(gè)方法:
public function createTokenDriver($name, $config)
{
// The token guard implements a basic API token based guard implementation
// that takes an API token field from the request and matches it to the
// user in the database or another persistence layer where users are.
$guard = new TokenGuard(
$this->createUserProvider($config['provider'] ?? null),
$this->app['request']
);
$this->app->refresh('request', $guard, 'setRequest');
return $guard;
}
顯然,api守衛(wèi)默認(rèn)的驅(qū)動(dòng)就是TokenGuard。
解讀 TokenGuard
/**
* Create a new authentication guard.
*
* @param \Illuminate\Contracts\Auth\UserProvider $provider
* @param \Illuminate\Http\Request $request
* @param string $inputKey
* @param string $storageKey
* @return void
*/
public function __construct(UserProvider $provider, Request $request, $inputKey = 'api_token', $storageKey = 'api_token')
{
$this->request = $request;
$this->provider = $provider;
$this->inputKey = $inputKey;
$this->storageKey = $storageKey;
}
/**
* Get the currently authenticated user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
// If we've already retrieved the user for the current request we can just
// return it back immediately. We do not want to fetch the user data on
// every call to this method because that would be tremendously slow.
if (! is_null($this->user)) {
return $this->user;
}
$user = null;
$token = $this->getTokenForRequest();
if (! empty($token)) {
$user = $this->provider->retrieveByCredentials(
[$this->storageKey => $token]
);
}
return $this->user = $user;
}
從構(gòu)造函數(shù)和 user() 方法中可以看出,默認(rèn)使用
['api_token' => $token]
這個(gè)數(shù)組去獲取用戶,也就是說,在用戶表中我們需要一個(gè)字段(默認(rèn)api_token)去存儲(chǔ)標(biāo)識(shí)用戶的 token。
開始使用 token 進(jìn)行api認(rèn)證
添加數(shù)據(jù)表字段
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddUsersApiTokenField extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('api_token', 60)->unique()->nullable()->after('password');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('api_token');
});
}
}
創(chuàng)建登錄控制器
這里不演示注冊(cè)之類的,假設(shè)我們的 users 表中已經(jīng)存在用戶,先創(chuàng)建一個(gè)用于 api 登錄的控制器。在每次登錄的時(shí)候,更新一次用戶的 api_token 。這里使用了 ThrottlesLogins ,用來控制登錄的嘗試次數(shù)。
namespace App\Http\Controllers\Api;
use Hash;
use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
use ThrottlesLogins;
/**
* @param Request $request
* @return \Illuminate\Http\Response|void
* @throws ValidationException
*/
public function login(Request $request)
{
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
return $this->sendLockoutResponse($request);
}
return $this->attempLogin($request);
}
/**
* @param Request $request
*/
public function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string'
]);
}
/**
* @param Request $request
* @return \Illuminate\Http\Response|void
*/
protected function attempLogin(Request $request)
{
$this->incrementLoginAttempts($request);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return $this->sendFailedLoginResponse($request);
}
// 更新 api_key
$api_token = uniqid($user->id);
$user->api_token = $api_token;
$user->save();
return $this->sendLoginResponse($request, $user);
}
/**
* @param Request $request
*/
protected function sendFailedLoginResponse(Request $request)
{
throw ValidationException::withMessages([
$this->username() => [trans('auth.failed')],
]);
}
/**
* @param Request $request
* @param User $user
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request, User $user)
{
$this->clearLoginAttempts($request);
return \Response::make([
'user' => $user,
'token' => $user->api_token
]);
}
public function username()
{
return 'email';
}
}
添加登錄路由
將 routes\api.php 修改如下:
Route::namespace('Api')->group(function () {
Route::post('login', 'LoginController@login');
}); # 登錄路由
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
調(diào)試
測(cè)試之前先往 users 表中添加幾個(gè)用戶,以下是我的測(cè)試數(shù)據(jù)。
可以看到登錄成功并且返回了 token 。
接下去我們使用獲取到的 token 請(qǐng)求需要登錄的接口,默認(rèn)有一個(gè),就是/user.
ok~ 已經(jīng)成功返回了數(shù)據(jù),說明登錄成功了!
例子中,api_token 是通過 OAuth 2.0 Access Token 的形式傳進(jìn)去的,但這不是唯一的方法,可以查看 TokenGuard 中的 getTokenForRequest 這個(gè)方法,它告訴我們可以用四種不同的形式傳入 api_token
總結(jié)
默認(rèn)的 api token 認(rèn)證雖然在文檔中沒有提及如何使用,但是通過查看代碼,也很容易使用。但是,在我們不重寫或者擴(kuò)展 tokenGUard的情況下,api_token 簡(jiǎn)直就是裸奔,顯然不可能就這樣應(yīng)用到項(xiàng)目中去。個(gè)人猜測(cè),框架中提供這個(gè)功能是為了讓我們更好的理解 api 認(rèn)證的工作原理,方便我們開發(fā)自己需要的 guard ,而且官方文檔也推薦我們使用 passport 或者 jwt 進(jìn)行 api 認(rèn)證。
本文出于個(gè)人對(duì)默認(rèn)配置的好奇進(jìn)而探究之后寫下的一片文章,也借鑒了網(wǎng)上的部分文章(忘記查看的文章地址了,也懶得找了),如有理解不到位或者錯(cuò)誤的,請(qǐng)!斧!正!
歡迎任何形式轉(zhuǎn)載,記得注明出處哦!
本作品采用《CC 協(xié)議》,轉(zhuǎn)載必須注明作者和本文鏈接
總結(jié)
以上是生活随笔為你收集整理的oracle access manager token,Laravel 自带的 API 守卫驱动 token 使用详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle服务未启动失败,window
- 下一篇: 印度智能手机市场最新排名:三星第一 国产