codewiser / oauth2-resource-server
OAuth 2.0 资源服务器
Requires
- laravel/framework: >=6.0
- league/oauth2-client: ^2.0
Requires (Dev)
- orchestra/testbench: ^6.3
Suggests
- ipunkt/laravel-oauth-introspection: Brings RFC 7662 to your Laravel Passport
This package is auto-updated.
Last update: 2023-11-23 14:17:20 UTC
README
OAuth 是一个授权服务器。它提供并验证令牌。它是构建分布式 API 基础设施的最佳解决方案。
基础设施可能包括许多 API 服务器,称为资源服务器。这些服务器接受的每个请求都必须包含授权信息——授权服务器签发的 access_token
。
每个资源服务器都是 OAuth 客户端。它拥有 client_id
和 client_secret
,可以使用 client_credentials
授予权限签发自己的 access_token
。另一方面,它可能是一个个人 access_token
,通过传统方式由用户签发。签发 access_token
后,服务器将使用它向邻居(同一基础设施中的其他资源服务器)发出请求,或提供对本地资源的访问。
当服务器收到包含授权信息的请求时,它将检查(参见 rfc7662)请求中的 access_token
。API 服务器调用 OAuth 服务器,并从它那里接收有关给定 access_token
的信息。
如果令牌有效且具有适当的范围,服务器将处理请求。如果不这样做,服务器将返回错误。
RFC
- 令牌检查
https://tools.ietf.org/html/rfc7662 - Bearer 令牌使用
https://tools.ietf.org/html/rfc6750
基于 league/oauth2-client 的包
先决条件
您的 OAuth 服务器必须实现 rfc7662(令牌检查端点)。请参阅 ipunkt/laravel-oauth-introspection。
安装
composer require codewiser/oauth2-resource-server
发布包配置。
php artisan vendor:publish --provider="Codewiser\ResourceServer\Providers\ResourceServerServiceProvider"
设置
一个环境需要所有标准 OAuth 客户端属性。
OAUTH_SERVER=https://oauth.example.com CLIENT_ID=123 CLIENT_SECRET=*** SCOPE="read write"
SCOPE
是请求访问令牌的默认范围。
以下为可选的,有默认值。
REDIRECT_URI=oauth/callback AUTHORIZE_ENDPOINT=oauth/authorize TOKEN_ENDPOINT=oauth/token RESOURCE_OWNER_ENDPOINT=api/user INTROSPECTION_ENDPOINT=oauth/introspect
您可以提供完整的 URL 或仅路径。
外观和中间件
资源服务器
ResourceServer
是 OAuth-client 的一层,负责保持 Client Credentials Access Token
并保护 API 资源。
$accessToken = ResourceServer::getAccessToken();
这将返回缓存的(或新签发的)客户端访问令牌。使用它调用其他 API 服务器。
令牌可以发送为 Athorization
标头(参见 rfc6750#section-2.1),
作为 access_token
主体参数(参见 rfc6750#section-2.2)或
作为 access_token
查询参数(参见 rfc6750#section-2.3)。
然后您的服务器收到带有 Bearer 令牌的 API 请求,它应该在 OAuth-server 上检查令牌。
$introspected = ResourceServer::getIntrospectedToken($request->bearerToken());
简单地,您可以使用 ResourceServerMiddleware
保护路由。在 app/Http/Kernel.php
中以您喜欢的方式定义它。
protected $routeMiddleware = [ 'scope' => \Codewiser\ResourceServer\Http\Middleware\ResourceServerMiddleware::class, ];
然后保护您的路由。
Route::get('resource', 'ApiController@list')->middleware('scope:read'); class ApiController extends Controller { public function list(Request $request) { // Get user profile from OAuth server $owner = ResourceServer::getTokenOwner($request); // Your code here } }
否则,您可以使用中间件保护一组路由,并在控制器中验证范围。
Route::get('resource', 'ApiController@list')->middleware('scope'); class ApiController extends Controller { public function list(Request $request) { ResourceServer::introspect($request) ->validateScope('read'); // Your code here } }
如果请求未验证,则抛出的异常会渲染适当的响应(根据 rfc6750)。
OAuthClient
OAuthClient
是 OAuth-client 的一层,负责授权用户并保持他们的 Personal Access Token
。
if (!OAuthClient::hasAccessToken()) { // Will remeber current page to get user back here. OAuthClient::setReturnUrl($request->fullUrl()); // Set required scopes OAuthClient::setScope('read write email etc'); return redirect(OAuthClient::getAuthorizationUrl()) }
授权服务器将用户返回到 CallbackController
。您可以使用内置的或定义新的。
try { // Callback will exchange authorization_code to access_token and stores it into session. OAuthClient::callback($request); // Then return user back to the page we previously stores. return redirect(OAuthClient::getReturnUrl('/')); } catch (\Throwable $e) { }
因此,如果我们有个人访问令牌
,我们应该向用户提供所需信息。
if (OAuthClient::hasAccessToken()) { ResourceServer::getIntrospectedToken(OAuthClient::getAccessToken()) ->validateScope('read'); // Your code here }
以简单的方式,您可以使用PersonalAccessMiddleware
来保护路由。在app/Http/Kernel.php
中以您喜欢的方式定义它。
protected $routeMiddleware = [ 'private' => \Codewiser\ResourceServer\Http\Middleware\PersonalAccessMiddleware::class, ];
然后保护您的路由。
Route::get('profile', 'PersonalController@show')->middleware('private:read')
如果用户没有个人访问令牌
,他或她将被重定向到授权服务器。
缓存
所有令牌都会在本地缓存一段时间。