kdefives / oauth2-riot
为PHP League的OAuth 2.0客户端提供Riot (RSO) OAuth 2.0支持
Requires
- league/oauth2-client: ^2.0
Requires (Dev)
- eloquent/phony-phpunit: ^2.0
- php-coveralls/php-coveralls: ^2.1
- phpunit/phpunit: ^6.0
- squizlabs/php_codesniffer: ^2.0
README
为PHP League的OAuth 2.0客户端提供Riot (RSO) OAuth 2.0支持
Riot OAuth 2.0客户端提供商
感谢使用以下(Google提供商)作为示例构建此提供商。
此包为PHP League的OAuth 2.0客户端提供了Riot OAuth 2.0支持。
此包与以下包进行了测试:https://github.com/knpuniversity/oauth2-client-bundle。
以下是一个使用此包的用法示例。
以下版本的PHP受到支持。
- PHP 7.3
- PHP 7.4
使用RSO (Riot Sign On)通过Riot ID账户验证用户的包。
注意:要实现Riot RSO,将需要RSO账户客户端ID和客户端密钥。这些可以在RSO文档中找到: https://www.riotgames.com/en/DevRel/rso
要求
在您的knpu_oauth2_client.yaml中声明以下参数
- url_authorization(例如: https://riot.com/as/authorization.oauth2)
- url_token(例如: https://riot.com/as/token.oauth2)
- url_user_info(例如: https://riot.com/idp/userinfo.openid)
使用https://github.com/knpuniversity/oauth2-client-bundle的knpu_oauth2_client声明示例
# file : app\config\packages\knpu_oauth2_client.yaml knpu_oauth2_client: clients: # configure your clients as described here: https://github.com/knpuniversity/oauth2-client-bundle#configuration # will create service: "knpu.oauth2.client.foo_bar_oauth" # an instance of: KnpU\OAuth2ClientBundle\Client\OAuth2Client riot_oauth: type: generic provider_class: League\OAuth2\Client\Provider\Riot # optional: a class that extends OAuth2Client # client_class: Some\Custom\Client # optional: if your provider has custom constructor options provider_options: url_authorization: '%env(URL_AUTHORIZATION)%' url_token: '%env(URL_TOKEN)%' url_user_info: '%env(URL_USERINFO)%' # now, all the normal options! client_id: '%env(riot_client_id)%' client_secret: '%env(riot_client_secret)%' redirect_route: connect_riot_check redirect_params: {}
安装
要安装,请使用composer
composer require kdefives/oauth2-riot
用法
以下是一个用法示例。请阅读knpuniversity/oauth2-client-bundle的README文档了解如何集成提供者: https://github.com/knpuniversity/oauth2-client-bundle
使用Symfony 5.2.2的授权代码流示例(与PHP-7.4进行测试)
认证器声明
<?php // app/src/Security/RiotAuthenticator.php namespace App\Security; use App\Entity\Player; use Doctrine\ORM\EntityManagerInterface; use KnpU\OAuth2ClientBundle\Client\OAuth2ClientInterface; use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator; use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use League\OAuth2\Client\Provider\RiotUser; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Util\TargetPathTrait; /** * Class RiotAuthenticator used for Riot RSO authentication using knpuniversity/oauth2-client-bundle * @package App\Security */ class RiotAuthenticator extends SocialAuthenticator { use TargetPathTrait; private $clientRegistry; private $em; private $router; public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $em, RouterInterface $router) { $this->clientRegistry = $clientRegistry; $this->em = $em; $this->router = $router; } public function supports(Request $request) { // continue ONLY if the current ROUTE matches the check ROUTE return $request->attributes->get('_route') === 'connect_riot_check'; } public function getCredentials(Request $request) { // this method is only called if supports() returns true // For Symfony lower than 3.4 the supports method need to be called manually here: // if (!$this->supports($request)) { // return null; // } return $this->fetchAccessToken($this->getRiotClient()); } public function getUser($credentials, UserProviderInterface $userProvider) { /** @var RiotUser $riotUser */ $riotUser = $this->getRiotClient() ->fetchUserFromToken($credentials); // We check we have a matching user in our database, then return the user return $this->em->getRepository(Player::class)->findOneBy( ['puuid' => $riotUser->getPuuid()] ); // If return null, login should fail //return null; } /** * @return OAuth2ClientInterface */ private function getRiotClient() { return $this->clientRegistry // "facebook_main" is the key used in config/packages/knpu_oauth2_client.yaml ->getClient('riot_oauth'); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { // Get initial target URI before redirection to RSO (login page or refresh token) $targetPath = $this->getTargetPath($request->getSession(), $providerKey); // Redirect to homepage by default if (!$targetPath) { $targetPath = $this->router->generate('homepage.display'); } return new RedirectResponse($targetPath); // or, on success, let the request continue to be handled by the controller //return null; } public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { //$message = strtr($exception->getMessageKey(), $exception->getMessageData()); //return new Response($message, Response::HTTP_FORBIDDEN); // Redirect to homepage return new RedirectResponse( '/', // might be the site, where users choose their oauth provider ); } /** * Called when authentication is needed, but it's not sent. * This redirects to the 'login'. * @param Request $request * @param AuthenticationException|null $authException * @return RedirectResponse */ public function start(Request $request, AuthenticationException $authException = null) { return new RedirectResponse( '/connect/', // might be the site, where users choose their oauth provider Response::HTTP_TEMPORARY_REDIRECT ); } }
控制器声明
<?php // app/src/Controller/RiotRsoController.php namespace App\Controller; use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; /** * Class RiotRsoController * @package App\Controller */ class RiotRsoController extends AbstractController { /** * Link to this controller to start the "connect" process * * @Route("/connect", name="connect_riot_start") * * @param ClientRegistry $clientRegistry * @return RedirectResponse */ public function connectAction(ClientRegistry $clientRegistry) { // on Symfony 3.3 or lower, $clientRegistry = $this->get('knpu.oauth2.registry'); // will redirect to Riot RSO return $clientRegistry ->getClient('riot_oauth') // key used in config/packages/knpu_oauth2_client.yaml ->redirect( ['openid'], // the scopes you want to access [] ); } /** * After going to Riot RSO, you're redirected back here * because this is the "redirect_route" you configured * in config/packages/knpu_oauth2_client.yaml * * @Route("/riot-oauth/callback", name="connect_riot_check") * * @param Request $request * @param ClientRegistry $clientRegistry */ public function connectCheckAction(Request $request, ClientRegistry $clientRegistry) { // ** if you want to *authenticate* the user, then // leave this method blank and create a Guard authenticator // (read below) //return new Response("<html>Hello World</html>"); } }
Guard认证器声明(security.yaml)
# app/config/packages/security.yaml security: # https://symfony.com.cn/doc/current/security.html#where-do-users-come-from-user-providers providers: # used to reload user from session & other features (e.g. switch_user) #in_memory: { memory: ~ } app_user_provider: entity: class: App\Entity\Player property: id firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: #anonymous: ~ anonymous: true lazy: true provider: app_user_provider # activate different ways to authenticate # https://symfony.com.cn/doc/current/security.html#firewalls-authentication # https://symfony.com.cn/doc/current/security/impersonating_user.html # switch_user: true guard: authenticators: - App\Security\RiotAuthenticator # Easy way to control access for large sections of your site # Note: Only the *first* access control that matches will be used access_control: - { path: ^/something, role: IS_AUTHENTICATED_REMEMBERED } - { path: ^/something-else, role: IS_AUTHENTICATED_REMEMBERED } - { path: ^/*, role: IS_AUTHENTICATED_ANONYMOUSLY }
用于认证的实体
<?php // app/src/Entity/Player.php namespace App\Entity; use App\Repository\PlayerRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * @ORM\Entity(repositoryClass=PlayerRepository::class) */ class Player implements UserInterface { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string", length=255, unique=true) * * A PUUID should never change (even if region transfers become a thing for val too) */ private $puuid; public function getId(): ?int { return $this->id; } public function getPuuid(): ?string { return $this->puuid; } public function setPuuid(string $puuid): self { $this->puuid = $puuid; return $this; } /** * @inheritDoc */ public function getRoles(): array { //$roles = $this->roles; // guarantee every user at least has ROLE_USER $roles[] = 'ROLE_USER'; return array_unique($roles); } /** * @inheritDoc */ public function getPassword(): ?string { return null; } /** * @inheritDoc */ public function getSalt(): ?string { return null; } /** * @inheritDoc */ public function getUsername(): string { return $this->puuid; } /** * @inheritDoc */ public function eraseCredentials() { // If you store any temporary, sensitive data on the user, clear it here // $this->plainPassword = null; } }
测试
可以使用以下命令运行测试
composer test
可以使用以下命令运行风格检查
composer check
如何贡献
如果您想快速在本地主机克隆、开发和测试,可以按照以下步骤操作。确实,您必须具有git和docker(例如Windows上的Docker Desktop)才能进行操作。
git clone ...
cd oauth2/riot
docker-compose build
docker-compose up -d php-fpm-riot-oauth2
docker-compose exec php-fpm-riot-oauth2 bash
composer test