bigfork / silverstripe-oauth
SilverStripe OAuth2认证,基于PHP League的OAuth2客户端
Requires
- league/oauth2-client: ^2
- silverstripe/framework: ^4 | ^5
Requires (Dev)
- phpunit/phpunit: ^5.7
README
SilverStripe OAuth2认证,基于PHP League的OAuth2客户端。
本模块的功能
此模块包括获取访问令牌的基本功能。它提供向OAuth提供者创建请求、使用各种范围/权限获取访问令牌以及为处理返回的令牌注册处理程序的方法。
本模块不做什么
此模块不提供“通过 <提供者> 登录”按钮、“从 <提供者> 获取联系人”按钮或与其他提供者交互的任何其他功能 - 它只获取允许您执行此操作的令牌。您需要安装适当的第三方提供者包,并实现利用访问令牌从这些提供者获取数据的功能。
如果您正在寻找“通过 <提供者> 登录”功能,请查看此模块的附加组件:SilverStripe OAuth Login。
此模块也不在数据库中存储访问令牌。如果这是您应用程序的要求,您需要构建自己的模型来处理此问题,并设置适当的令牌处理程序。
安装
必须使用composer安装此模块。在命令行中运行composer require bigfork/silverstripe-oauth:*
,然后运行dev/build
。
配置
使用SilverStripe的YAML配置将提供者注册为Injector
服务。这允许您指定“内部”名称(在URL和会话数据中传递),提供者的PHP类(扩展League\OAuth2\Client\Provider\AbstractProvider
)以及构造函数参数和类属性。
例如,要设置Facebook作为提供者,首先安装Facebook OAuth2包,然后向您的YAML配置中添加以下内容
SilverStripe\Core\Injector\Injector: Bigfork\SilverStripeOAuth\Client\Factory\ProviderFactory: properties: providers: 'Facebook': '%$FacebookProvider' FacebookProvider: class: 'League\OAuth2\Client\Provider\Facebook' constructor: Options: clientId: '12345678987654321' clientSecret: 'geisjgoesingoi3h1521onnro12rin' graphApiVersion: 'v2.6'
注意,在上面的示例中,缺少必要的redirectUri
构造函数参数。此模块将自动更新服务配置,为所有提供者添加此参数,以节省在环境/域名之间移动时更新URL的需要。如果存在redirectUri
参数,则不会覆盖它。
使用方法
如果您正在寻找“通过 <提供者> 登录”功能,请查看此模块的附加组件:SilverStripe OAuth Login。
为了实际与OAuth令牌交互,您需要在回调过程中注册一个令牌处理程序(实现Bigfork\SilverStripeOAuth\Client\Handler\TokenHandler
),以执行此操作。每个处理程序都有一个可选的数字优先级(用于控制它们被调用的顺序),以及一个“上下文”。上下文选项用于确保处理程序仅在执行某些操作时运行,并匹配在发行令牌请求时指定的上下文参数(请参阅辅助部分)。注册上下文为*
的处理程序将始终被调用,无论提供的上下文如何。
以下是一个负责从用户Facebook个人资料获取事件并注册它的令牌处理程序的示例。我们使用上下文参数来确保处理程序仅在执行此操作时运行(例如,我们不希望在用户登录时运行它)。
在这里,我们注册了一个名为 import_events
的上下文的令牌处理器。
Bigfork\SilverStripeOAuth\Client\Control\Controller: token_handlers: importeventshandler: priority: 1 context: 'import_events' class: 'ImportEventsHandler'
接下来,我们需要构建一个指定该上下文的授权 URL。
use Bigfork\SilverStripeOAuth\Client\Helper\Helper; // Build a URL for fetching a Facebook access token with the required 'user_events' permission // Will return a URL like: http://mysite.com/oauth/authenticate/?provider=Facebook&context=import_events&scope%5B2%5D=user_events $url = Helper::buildAuthorisationUrl('Facebook', 'import_events', ['user_events']); echo "<a href=" . $url . ">Import events from Facebook</a>";
当用户从 Facebook 返回时,我们的令牌处理器将在回调过程中被调用。
use Bigfork\SilverStripeOAuth\Client\Handler\TokenHandler; use League\OAuth2\Client\Provider\Facebook; use League\OAuth2\Client\Token\AccessToken; class ImportEventsHandler implements TokenHandler { public function handleToken(AccessToken $token, Facebook $provider) { $baseUrl = 'https://graph.facebook.com/v2.8'; $params = http_build_query([ 'fields' => 'id,name,start_time', 'limit' => '5', 'access_token' => $token->getToken(), 'appsecret_proof' => hash_hmac('sha256', $token->getToken(), '{facebook-app-secret}'), ]); $response = file_get_contents($baseUrl.'/me/events?'.$params); $data = json_decode($response, true); $this->importEvents($data); } }
从 handleToken()
方法抛出异常将导致所有其他处理器被取消,异常信息将被记录,并向用户显示一个 "400 Bad Request" 错误页面。该方法还可以返回一个 SS_HTTPResponse
实例,该实例将在所有剩余处理器运行后输出到浏览器。
错误处理
有时,OAuth 提供商可能会返回由用户引起的错误。最常见的例子是当用户拒绝授予您请求的权限时。由于每个提供商以不同的方式提供错误消息,您需要构建自己的错误处理逻辑。错误处理器可以像令牌处理器一样注册,例如
Bigfork\SilverStripeOAuth\Client\Control\Controller: error_handlers: importeventserrorhandler: priority: 1 context: 'import_events' class: 'ImportEventsErrorHandler'
use Exception; use League\OAuth2\Client\Provider\AbstractProvider; use SilverStripe\Control\HTTPRequest; use SilverStripe\Security\Security; class ImportEventsErrorHandler implements ErrorHandler { public function handleError(AbstractProvider $provider, HTTPRequest $request, Exception $exception) { if ($request->getVar('error_message')) { return Security::permissionFailure(null, $request->getVar('error_message')); } } }
错误记录
默认情况下,致命的 OAuth 错误将被记录到 PHP 的错误日志中。您可以通过覆盖 Psr\Log\LoggerInterface.oauth:
注入器服务定义来设置自己的日志记录。例如,要将错误记录到 oauth.log
文件中
--- After: silverstripe-oauth-logging --- SilverStripe\Core\Injector\Injector: Psr\Log\LoggerInterface.oauth: calls: null # Reset - without this, the below "calls" would be merged in instead of replacing the original --- After: silverstripe-oauth-logging --- SilverStripe\Core\Injector\Injector: Psr\Log\LoggerInterface.oauth: calls: pushDisplayErrorHandler: [ pushHandler, [ '%$OAuthLogFileHandler' ] ] OAuthLogFileHandler: class: Monolog\Handler\StreamHandler constructor: - '../oauth.log' - 'error'
SameSite / POST cookies
一些提供商,如 Apple,将使用 POST 请求重定向回您的网站。当这种情况发生时,默认的浏览器行为是不将cookie与请求一起发送,这意味着无法验证请求,因为用户的会话已丢失。有两种方法可以解决这个问题
- 按照以下方式标记您的会话cookie为
SameSite=None; Secure
,详情请见 这里 - 设置以下 YAML 值
Bigfork\SilverStripeOAuth\Client\Control\Controller: enable_samesite_workaround_redirect: true
当此功能启用时,您的网站将处理从 OAuth 提供商接收到的 POST 请求,通过重定向用户进行 GET 请求。当发出此 GET 请求时,网站再次可以访问用户的会话 cookie,因此授权过程可以像平常一样继续。