beyondbluesky/oauth2-pkce-client

使用PKCE的OAuth2客户端实现

1.3.8 2023-11-07 05:14 UTC

This package is auto-updated.

Last update: 2024-09-07 07:09:31 UTC


README

这个Symfony扩展允许Symfony4/5/6安装通过使用PKCE扩展来验证OAuth2服务器上的用户。

PKCE扩展RFC-7636 (https://tools.ietf.org/html/rfc7636)为OAuth2协议增加了额外的安全性,并在OAuth2的未来版本中将成为强制性。

此实现需要生成以下内容:

  • 认证器
  • 控制器以接收来自OAuth2服务器的响应
  • 存储会话信息(oauth2_session)的表。该表用于存储会话信息,包括挑战和验证器字符串,用于在PKCE扩展部分中保护通信。
  • 存储client_id、oauth2 uris等信息的所需配置文件。
  • 修改security.yml以包含所有之前配置的配置

以下将列出配置它的所有步骤。别担心...

安装

要安装它,您需要按照以下步骤操作

  1. 下载扩展的最新版本
$ composer require beyondbluesky/oauth2-pkce-client 
  1. 使用名为config/packages的文件配置您的OAuth2服务器的端点

config/packages/oauth2_pkce_client.yaml

oauth2_pkce_client:
    server_uris:
        auth_uri:   https://oauth2.localnet/oauth2/auth
        token_uri:  https://oauth2.localnet/oauth2/token
        owner_uri:  https://oauth2.localnet/oauth2/owner
    client:
        id: client_id_provided from our oauth2 server
        secret: secret provided from our oauth2 server
        scope: 'authorization_code,user_info,user_auth'
        redirect_uri: https://oauth2client.localnet/oauth2/check
  1. 创建一个控制器来接收令牌,该控制器必须与redirect_uri路径匹配。以下是一个示例代码,您可以根据需要进行修改

src/Controller/OAuth2Controller.php

namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

use BeyondBlueSky\OAuth2PKCEClient\Entity\OAuth2Session;
use BeyondBlueSky\OAuth2PKCEClient\DependencyInjection\OAuth2PKCEClientExtension as OAuth2PKCEClient;

/**
 * Default App controller.
 *
 * @Route("/oauth2")
 */
class OAuth2Controller extends AbstractController
{
    
    /**
     * @Route("/login", name="oauth_login", methods={"GET"})
     */ 
    public function oauthLogin(Request $request, OAuth2PKCEClient $oauth2)
    {
        
        $session = new OAuth2Session();
        $response= $oauth2->getAuthRedirect($session);

        $this->getDoctrine()->getManager()->persist($session);
        $this->getDoctrine()->getManager()->flush();
        
        return $response;
    }
    
    /**
     * @Route("/check", name="oauth_check", methods={"GET"})
     */ 
    public function oauthRedirect(Request $request)
    {
        $user= $this->getUser();
        if ($user == null ) {
            return new Response(json_encode( ['status' => false, 'message' => "User not found!"] ) );
        } else {
            return $this->redirectToRoute('homepage');
        }
    }
    
}
  1. 创建一个用户类。最小信息应该是用户名。所有其他字段都是可选的,并在本指南的第5点中填充。在我们的情况下,我们将在Entity文件夹中创建一个Security\User。

如果您是初学者,我强烈建议您使用以下命令

$ bin/console make:entity

并遵循提出的问题,添加用户名字段以及您项目需要的所有字段。这将生成一个配置了所有所需信息的ORM配置实体。

创建您的用户后,编辑它并实现UserInterface接口,以告诉Symfony您的用户实体是Symfony用户

class User implements \Symfony\Component\Security\Core\User\UserInterface

实现UserInterface后,您必须添加一些Symfony函数

    public function getRoles(): array {
        
        return ['ROLE_USER'];
    }
    
    public function getPassword() {
        return "-";
    }
    
    public function getSalt() {
        return 1;
    }
    public function eraseCredentials() {
        return ;
    }
    
    public function getUsername(): string {
        return $this->email;
    }
  1. 现在我们需要一个新的认证器。使用以下代码作为模板。请考虑getUser函数,您必须用从您的OAuth2服务器收到的字段填写您的用户对象。如果您不确定接收到了什么,可以var_dump oauthUser

src/Security/OAuth2Authenticator.php

namespace App\Security;

use App\Entity\Security\User;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserProviderInterface;

use Doctrine\ORM\EntityManagerInterface;

use BeyondBlueSky\OAuth2PKCEClient\DependencyInjection\OAuth2PKCEClientExtension as OAuth2PKCEClient;
use BeyondBlueSky\OAuth2PKCEClient\Security\OAuth2PKCEAuthenticator;

/**
 */
class OAuth2Authenticator extends OAuth2PKCEAuthenticator
{
    public function supports(Request $request): bool{
        return $request->getPathInfo() == '/oauth2/check' && $request->isMethod('GET');
    }
    
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        // With this function we fetch the user's data from the credentials
        $oauthUser = $this->fetchUser($credentials);
    
        $login = $oauthUser->login;
        $user = $this->em->getRepository(User::class)->findOneBy(['username' => $login]);
            
        if (! $user ) {
            // Now we have to adapt to our local User 
            $user = new User();
            $user->setUsername($oauthUser->login);
            $user->setEmail($oauthUser->email);
            $user->setName($oauthUser->name);
            $user->setSurname1($oauthUser->surname1);
            $user->setSurname2($oauthUser->surname2);
            $user->setPassword('-');
            $user->setRoles(['ROLE_USER']);
            //$user->setFullname($oauthUser['name']. " ".$oauthUser['surname1']. " ".$oauthUser['surname2']);
            $user->setCreatedAt(new \DateTime(date('Y-m-d H:i:s')));
            $this->em->persist($user);
            $this->em->flush();
        }
        return $user;   
    }   
}
  1. 更新您的数据库模式:schema:update或doctrine:migrations,您选择。
$ bin/console doctrine:schema:update --force
  1. 配置security.yaml以指向我们新的认证器

在提供商部分中,将内存中的行替换为

config/packages/security.yaml

        oauth_user_provider:
            entity:
                class: App\Entity\Security\User
                property: username

在firewalls > main中,引用您的新用户提供程序并添加我们在步骤5中创建的认证器

    firewalls:
        main:
            anonymous: lazy
            provider: oauth_user_provider
            guard:
                authenticators:
                    - App\Security\OAuth2Authenticator
  1. 享受您的新OAuth2认证!为了做到这一点,请转到您的Symfony根目录并在浏览器中向URL添加oauth2/login(如果您没有更改OAuth2Controller中的路径)。现在您应该看到OAuth2服务器的登录页面。

祝您玩得开心!