ridibooks/ oauth2
Ridibooks OAuth2
v0.3.1
2020-01-06 01:41 UTC
Requires
Requires (Dev)
- mockery/mockery: ^1.3
- phpunit/phpunit: ^7
Suggests
- guzzlehttp/guzzle: Required when using `Ridibooks\OAuth2\Silex\Provider\DefaultUserProvider`or `Ridibooks\OAuth2\Symfony\Provider\DefaultUserProvider`
- silex/silex: Required when using `Ridibooks\OAuth2\Silex\Provider\OAuth2ServiceProvider`(compatible with 1.3.x versions)
- symfony/symfony: Required when using `Ridibooks\OAuth2\Symfony\OAuth2ServiceProviderBundle`(compatible with 4.x.x versions)
README
介绍
- 这是一个用于构建OAuth2客户端和资源服务器的PHP库。
- 按照Ridi风格指南(内部服务间SSO)编写。
- 可选择支持JWK缓存。通过向JwtTokenValidator注入psr-6的实现体,可以使用缓存功能。
需求
PHP 7.2
或更高版本- 为了使用php7.2-gmp web-token解密模块,需要在操作系统内安装php7.2-gmp。因此,请务必在库客户端的操作系统或Docker镜像内安装。请参考PR。
silex/silex v1.3.x
(可选)symfony/symfony v4.x.x
(可选)guzzlehttp/guzzle
(可选)
安装
composer require ridibooks/oauth2
使用
无缓存JwtTokenValidator
use Ridibooks\OAuth2\Authorization\Validator\JwtTokenValidator; $access_token = '...'; try { $jwk_url = $this->configs['jwk_url']; $validator = new JwtTokenValidator($jwk_url); $validator->validateToken($access_token); } catch (AuthorizationException $e) { // handle exception }
带缓存JwtTokenValidator
use Ridibooks\OAuth2\Authorization\Validator\JwtTokenValidator; $access_token = '...'; try { $jwk_url = $this->configs['jwk_url']; $cache_item_pool = new FilesystemAdapter(); // [psr-6](https://www.php-fig.org/psr/psr-6/) Implementation Adaptor $validator = new JwtTokenValidator($jwk_url, $cache_item_pool); $validator->validateToken($access_token); } catch (AuthorizationException $e) { // handle exception }
范围检查器
$required = ['write', 'read']; if (ScopeChecker::every($required, $granted)) { // pass }
授权者
$client_info = new ClientInfo('client_id', 'client_secret', ['scope'], 'redirect_uri'); $auth_server_info = new AuthorizationServerInfo('authorization_url', 'token_url'); $granter = new Granter($client_info, $auth_server_info); $authorization_url = $granter->authorize(); // Redirect to `$authorization_url`
使用:与Silex提供者一起使用
将OAuth2ServiceProvider
注册到Silex应用程序中(使用register
方法)。
服务
OAuth2ProviderKeyConstant::GRANTER
authorize(string $state, string $redirect_uri = null, array $scope = null): string
:返回用于/authorize
的URL
OAuth2ProviderKeyConstant::AUTHORIZER
autorize(Request $request): JwtToken
:在检查access_token
的有效性后返回JwtToken
对象
OAuth2ProviderKeyConstant::MIDDLEWARE
authorize(OAuth2ExceptionHandlerInterface $exception_handler = null, UserProviderInterface $user_provider = null, array $required_scopes = [])
:返回中间件
示例:OAuth2ProviderKeyConstant::MIDDLEWARE
服务
use Ridibooks\OAuth2\Silex\Constant\OAuth2ProviderKeyConstant as KeyConstant; use Ridibooks\OAuth2\Silex\Handler\LoginRequiredExceptionHandler; use Ridibooks\OAuth2\Silex\Provider\OAuth2ServiceProvider; use Ridibooks\OAuth2\Authorization\Validator\JwtTokenValidator; use Example\UserProvder; // `OAuth2ServiceProvider` 등록 $app->register(new OAuth2ServiceProvider(), [ KeyConstant::CLIENT_ID => 'example-client-id', KeyConstant::CLIENT_SECRET => 'example-client-secret', KeyConstant::JWT_VALIDATOR => new JwtTokenValidator($jwk_url) ]); // 미들웨어 등록 $app->get('/auth-required', [$this, 'authRequiredApi']) ->before($app[KeyConstant::MIDDLEWARE]->authorize(new LoginRequiredExceptionHandler(), new UserProvider()); public function authRequiredApi(Application $app) { // 사용자 추출 $user = $app[KeyConstant::USER]; ... }
示例:OAuth2ProviderKeyConstant::AUTHORIZER
服务
use Ridibooks\OAuth2\Authorization\Authorizer; use Ridibooks\OAuth2\Authorization\Exception\AuthorizationException; use Ridibooks\OAuth2\Silex\Constant\OAuth2ProviderKeyConstant; use Ridibooks\OAuth2\Silex\Provider\OAuth2ServiceProvider; use Silex\Application; use Symfony\Component\HttpFoundation\Request; use Ridibooks\OAuth2\Authorization\Validator\JwtTokenValidator; ... // `OAuth2ServiceProvider` 등록 $app->register(new OAuth2ServiceProvider(), [ KeyConstant::CLIENT_ID => 'example-client-id', KeyConstant::CLIENT_SECRET => 'example-client-secret', KeyConstant::JWT_VALIDATOR => new JwtTokenValidator($jwk_url) ]); ... $app->get('/', function (Application $app, Request $request) { /** @var Authorizer $authorizer */ $authorizer = $app[OAuth2ProviderKeyConstant::AUTHORIZER]; try { $token = $authorizer->authorize($request); return $token->getSubject(); } catch (AuthorizationException $e) { // handle authorization error ... } });
使用:与Symfony包一起使用
服务
Granter()
OAuth2ServiceProvider::getGranter()
Granter::authorize(string $state, string $redirect_uri = null, array $scope = null): string
:返回用于/authorize
的URL
Authorizer()
OAuth2ServiceProvider::getAuthorizer()
Authorizer::autorize(Request $request): JwtToken
:在检查access_token
的有效性后返回JwtToken
对象
OAuth2Middleware
OAuth2ServiceProvider::getMiddleware()
- 在创建
OAuth2ServiceProvider
时,作为Symfony事件订阅者进行注册
示例:OAuth2Middleware
服务
配置
- 配置示例可以在
tests/Symfony
中查看。
1. 注册OAuth2ServiceProviderBundle
# example: <project_root>/config/bundles.php return [ ..., Ridibooks\OAuth2\Symfony\OAuth2ServiceProviderBundle::class => ['all' => true] ];
2. 参数和服务设置
- 可以使用
'%env(VARIABLE)%'
来使用环境变量。 - 必需
- client_id
- client_secret
- authorize_url
- token_url
- jwk_url
- user_info_url
- token_cookie_domain
- default_exception_handler
- 可选
- client_default_scope
- client_default_redirect_uri
- default_user_provider
- cache_item_pool # 如果注入psr-6的实现体,则在使用Jwk请求时可以使用缓存功能。
# example: <project_root>/config/packages/o_auth2_service_provider.yml o_auth2_service_provider: client_id: '%env(CLIENT_ID)%' client_secret: '%env(CLIENT_SECRET)%' authorize_url: https://account.dev.ridi.io/ridi/authorize/ token_url: https://account.dev.ridi.io/oauth2/token/ jwk_url: https://account.dev.ridi.io/oauth2/keys/public user_info_url: https://account.dev.ridi.io/accounts/me/ token_cookie_domain: .ridi.io default_exception_handler: Ridibooks\OAuth2\Example\DefaultExceptionHandler cache_item_pool: Symfony\Component\Cache\Adapter\FilesystemAdapter
# example: <project_root>/config/services.yml services: Ridibooks\OAuth2\Example\ExampleController: class: Ridibooks\OAuth2\Example\ExampleController autowire: true autoconfigure: true public: false arguments: - '@oauth2_service_provider'
3. 控制器设置
namespace Ridibooks\OAuth2\Example; use Ridibooks\OAuth2\Symfony\Annotation\OAuth2; use Ridibooks\OAuth2\Symfony\Provider\OAuth2ServiceProvider; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; class ExampleController extends Controller { /** @var OAuth2ServiceProvider */ private $oauth2_service_provider; /** * @param OAuth2ServiceProvider $oauth2_service_provider */ public function __construct(OAuth2ServiceProvider $oauth2_service_provider) { $this->oauth2_service_provider = $oauth2_service_provider; } /** * @Route("/oauth2", methods={"GET"}) * @OAuth2() * * @param Request $request * @return Response */ public function normal(Request $request): Response { $user = $this->oauth2_service_provider->getMiddleware()->getUser(); return new JsonResponse([ 'u_idx' => $user->getUidx(), 'u_id' => $user->getUid() ]); } }
OAuth2异常处理器设置
- 异常处理器负责处理OAuth2过程中发生错误时的异常情况。
- 如果想要在Application Controller中使用除默认的
default_exception_handler
参数外的其他Exception Handler,请遵循以下步骤:- 创建一个实现了
Ridibooks\OAuth2\Symfony\Handler\OAuth2ExceptionHandlerInterface
的Exception Handler。- 示例:
Ridibooks\Test\OAuth2\Symfony\TestExceptionHandler
- 示例:
- 在Application Controller的
@OAuth2
注解中指定exception_handler
属性。- 示例:
@OAuth2(exception_handler="Ridibooks\Test\OAuth2\Symfony\TestExceptionHandler")
- 示例:
- 创建一个实现了
自定义用户提供者设置
- 用户提供者在认证之后负责获取用户信息。
- 如果没有指定
default_user_provider
参数,则默认使用Ridibooks\OAuth2\Symfony\Provider\DefaultUserProvider
。 - 如果想要在 Application Controller 中使用指定为
default_user_provider
的 User Provider 而不是其他 User Provider,请按照以下步骤操作。- 创建实现了
Ridibooks\OAuth2\Symfony\Provider\UserProviderInterface
的 User Provider。 - 在 Application Controller 的
@OAuth2
注解中指定user_provider
属性。
- 创建实现了
namespace Ridibooks\OAuth2\Example; use Ridibooks\OAuth2\Authorization\Token\JwtToken; use Ridibooks\OAuth2\Symfony\Provider\OAuth2ServiceProvider; use Ridibooks\OAuth2\Symfony\Provider\UserProviderInterface; use Symfony\Component\HttpFoundation\Request; class CustomUserProvider implement UserProviderInterface { /** * @param JwtToken $token * @param Request $request * @param OAuth2ServiceProvider $oauth2_service_provider * @return User */ public function getUser(JwtToken $token, Request $request, OAuth2ServiceProvider $oauth2_service_provider): User { ... } }
namespace Ridibooks\OAuth2\Example; use Ridibooks\OAuth2\Symfony\Annotation\OAuth2; use Ridibooks\OAuth2\Symfony\Provider\OAuth2ServiceProvider; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; class ExampleController extends Controller { /** * @Route("/oauth2", methods={"GET"}) * @OAuth2(user_provider="Ridibooks\OAuth2\Example\CustomUserProvider") * * @param Request $request * @return Response */ public function normal(Request $request): Response { ... } }
Cache Item Pool 设置
- Cache Item Pool 负责缓存 Jwk。
注意事项
- 不支持 Jwk Multi signatures。只获取第一个索引的签名并对其进行解码。
- Jwk Cache 文件的 TTL(Time To Live)是 5 分钟。