为 SPA(单页应用程序)、移动应用程序和基于令牌的、简单的 API 提供轻量级身份验证系统。
允许应用程序的每个用户为他们的帐户生成多个 API 令牌。 这些令牌可以被授予指定允许令牌执行哪些操作的权限。
为了解决两个独立问题而生
首先,它是一个简单的包,用于向用户发出 API 令牌,而不涉及 OAuth2
。
这个特性是通过将用户 API 令牌存储在单个数据库表中,并通过包含了有效 API 令牌的 Authorization
标识头对传入的请求进行身份验证而实现的。
其次,提供了一种简单的方法来认证需要与基于 Laravel
的 API 进行通信的单页应用程序 (SPAs)。
这些 SPAs 可能与 Laravel
应用程序存在于同一仓库中,也可能是一个完全独立的仓库,例如使用 Vue CLI
或者 Next.js
创建的单页应用。
您可以通过 Composer
软件包管理器安装:
composer require jundayw/laravel-oauth
接下来,你需要使用 vendor:publish
Artisan 命令发布的配置和迁移文件。
配置文件将会保存在 config 文件夹中:
php artisan vendor:publish --provider="Jundayw\LaravelOAuth\OAuthServiceProvider"
或单独发布配置文件
php artisan vendor:publish --tag=oauth-config
或单独发布迁移文件
php artisan vendor:publish --tag=oauth-migrations
最后,您应该运行数据库迁移。
php artisan migrate --path=database/migrations/2022_07_23_160710_create_oauth_table.php
如果你不想使用默认迁移,你应该在 App\Providers\AppServiceProvider
类的 register
方法中调用 OAuth::ignoreMigrations()
方法。
您可以通过执行以下命令导出默认迁移:
php artisan vendor:publish --tag=oauth-migrations
通常,您应该在应用程序的服务提供器的 boot
方法中调用此方法:
use App\Models\OAuthToken;
use Jundayw\LaravelOAuth\OAuth;
/**
* 引导应用程序服务。
*
* @return void
*/
public function boot()
{
OAuth::oAuthTokenModelUsing(OAuthToken::class);
}
通常,您应该在应用程序的服务提供器的 boot
方法中调用此方法:
use App\Models\RefreshToken;
use Jundayw\LaravelOAuth\OAuth;
/**
* 引导应用程序服务。
*
* @return void
*/
public function boot()
{
OAuth::refreshTokenModelUsing(RefreshToken::class);
}
配置文件 config/oauth.php
return [
// 加密秘钥
'secret' => env('OAUTH_SECRET', env('APP_KEY')),
// 加密方法
'hash' => 'sha256',
// 数据库存储令牌表
'table' => 'oauth',
// 访问令牌过期时间
'access_token_expire_in' => 2 * 3600,
// 刷新令牌过期时间
'refresh_token_expire_in' => 24 * 3600 * 15,
// 多[客户端/设备]是否同时在线,默认:开启
// 如:同一账户是否允许[手机/电脑]同时在线
'multiple_devices' => true,
// 相同[客户端/设备]是否同时在线,默认:开启
// 如:同一账户是否允许电脑端同时在线
'concurrent_device' => true,
];
配置文件 config/auth.php
中, 将授权看守器 guards
的 driver
参数的值设置为 oauth
。
return [
// ...
'guards' => [
// 如果只有一个 oauth 看守器 provider 可为 null
'client' => [
'driver' => 'oauth',
'provider' => null,
],
// 如果多个 oauth 看守器 provider 需要配置
'manager' => [
'driver' => 'oauth',
'provider' => 'managers',
],
'user' => [
'driver' => 'oauth',
'provider' => 'users',
],
],
'providers' => [
'managers' => [
'driver' => 'eloquent',
'model' => App\Models\Manager::class,
],
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
// ...
];
laravel
框架默认内置了(Sanctum
在处理 APP
开发时,无法实现令牌刷新功能)此时使用 OAuth
将造成冲突,解决方案:
使用 HasAccessTokens
功能替代 HasApiTokens
,如果你其他模块使用到了 Sanctum
use Jundayw\LaravelOAuth\Contracts\HasAccessTokensContract;
use Jundayw\LaravelOAuth\HasAccessTokens;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable implements HasAccessTokensContract
{
use HasApiTokens, HasAccessTokens {
HasAccessTokens::currentAccessToken insteadof HasApiTokens;
HasAccessTokens::withAccessToken insteadof HasApiTokens;
HasAccessTokens::createToken insteadof HasApiTokens;
HasAccessTokens::tokens insteadof HasApiTokens;
HasAccessTokens::tokenCan insteadof HasApiTokens;
}
}
也可以将 HasApiTokens
删除
use Jundayw\LaravelOAuth\Contracts\HasAccessTokensContract;
use Jundayw\LaravelOAuth\HasAccessTokens;
class User extends Authenticatable implements HasAccessTokensContract
{
use HasAccessTokens;
}
允许你发布 API 令牌,用于对你的应用程序的 API 请求进行身份验证。 使用 API 令牌发出请求时,令牌应作为 Bearer
令牌包含在 Authorization
请求头中。
use Jundayw\LaravelOAuth\Contracts\HasAccessTokensContract;
use Jundayw\LaravelOAuth\HasAccessTokens;
class User extends Authenticatable implements HasAccessTokensContract
{
use HasAccessTokens;
}
要发布令牌,你可以使用 createToken 方法。 createToken 方法返回一个 Jundayw\LaravelOAuth\Token
实例。
use Illuminate\Http\Request;
Route::post('/tokens/create', function(Request $request) {
return $request->user()
->createToken($request->token_name, $request->device_name, ['check-status', 'place-orders'])
->toArray();
});
你可以使用 HasAccessTokens
trait 提供的 tokens
Eloquent 关系访问用户的所有令牌:
foreach($user->tokens as $token) {
//
}
use Illuminate\Http\Request;
use Jundayw\LaravelOAuth\RefreshToken;
Route::post('/tokens/refresh', function(Request $request, RefreshToken $refreshToken) {
return $refreshToken->refreshToken($refreshToken->findTokenByRequest($request))->toArray();
});
OAuth
内置 scopes
及 scope
中间件:
scopes
中间件可以分配给一个路由,以验证传入请求的令牌是否具有所有列出的能力:
Route::get('/orders', function() {
// Token has both "check-status" and "place-orders" abilities...
})->middleware(['auth:client', 'scopes:check-status,place-orders']);
scope
中间件可以分配给一个路由,以验证传入请求的令牌是否具有至少一个列出的能力:
Route::get('/orders', function() {
// Token has the "check-status" or "place-orders" ability...
})->middleware(['auth:client', 'scope:check-status,place-orders']);
use Illuminate\Http\Request;
Route::middleware(['api', 'auth:client'])->get('/user', function(Request $request) {
return $request->user();
});
第一步:配置文件 config/auth.php
:
return [
// ...
'guards' => [
'manager' => [
'driver' => 'oauth',
'provider' => 'managers',
],
'user' => [
'driver' => 'oauth',
'provider' => 'users',
],
],
'providers' => [
'managers' => [
'driver' => 'eloquent',
'model' => App\Models\Manager::class,
],
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
// ...
];
第二步:实现接口
use Jundayw\LaravelOAuth\Contracts\HasAccessTokensContract;
use Jundayw\LaravelOAuth\HasAccessTokens;
class User extends Authenticatable implements HasAccessTokensContract
{
use HasAccessTokens;
}
use Jundayw\LaravelOAuth\Contracts\HasAccessTokensContract;
use Jundayw\LaravelOAuth\HasAccessTokens;
class Manager extends Authenticatable implements HasAccessTokensContract
{
use HasAccessTokens;
}
第三步:配置文件 routes/web.php
:
use App\Models\User;
use App\Models\Manager;
use Illuminate\Http\Request;
use Jundayw\LaravelOAuth\RefreshToken;
// 发布 user 令牌
Route::get('/user', function(User $user) {
return $user->first()?->createToken('测试-user', 'APP')->toArray();
});
// 发布 manager 令牌,有作用域
Route::get('/manager', function(Manager $manager) {
return $manager->first()
?->createToken('测试-manager', 'PC', ['snsapi_base', 'snsapi_userinfo'])
->toArray();
});
// 获取 user 当前账户
Route::middleware(['auth:user'])->post('/user-info', function(Request $request) {
return $request->user();
});
// 获取 manager 当前账户,验证作用域
Route::middleware(['auth:manager', ['scope:snsapi_userinfo']])
->post('/manager-info', function(Request $request) {
return $request->user();
});
// 刷新当前账户
Route::get('/refresh', function(\Illuminate\Http\Request $request, \Jundayw\LaravelOAuth\RefreshToken $refreshToken) {
return $refreshToken->refreshToken($refreshToken->findTokenByRefreshToken($request->bearerToken()))->toArray();
});