drenso/symfony-oidc-bundle

Symfony 的 OpenID connect 扩展包

安装量: 241,039

依赖者: 0

建议者: 0

安全性: 0

星标: 54

关注者: 4

分支: 32

公开问题: 2

类型:symfony-bundle

v3.4.0 2024-09-10 07:23 UTC

README

此扩展包可用于为任何 Symfony 应用程序添加 OIDC 支持。我们仅对其与 SURFconext OIDC 进行了测试,但它应该与任何 OIDC 提供商兼容!

感谢 https://github.com/jumbojett/OpenID-Connect-PHP 的实现,尽管此扩展包已修改以采用面向对象的方法。

注意,此存储库自动从我们的 Gitlab 实例镜像。尽管如此,我们仍将在此处理问题报告和合并请求!

版本说明

自版本 2 开始,此扩展包仅支持 Symfony 5.3 中引入的新认证管理器。随着 Symfony 5.4 中安全管理者的发展,这是此扩展包支持的第一个版本。使用新认证管理器对于 Symfony 6 是必需的!

我们还需要使用 PHP8,因为这显著降低了维护复杂性。

如果您需要此扩展包,但无法启用新认证管理器或使用 PHP8,请查看 v1.x 分支及其文档!

支持以下身份提供者 (IdP)

以下已知的身份提供者与该扩展包兼容

如果您使用此扩展包与任何其他身份提供者,请提交 PR 以添加它!

从旧版本迁移

请参阅 UPGRADE.md

安装

您可以通过 composer 简单地要求添加此扩展包

composer require drenso/symfony-oidc-bundle

如果您使用 Symfony Flex,则您的 .env 文件应已添加一些环境变量,并在您的配置目录中创建了一个 drenso_oidc.yaml 文件!

设置

OIDC 客户端

请确保在您的 config/packages 目录中的 drenso_oidc.yaml 中配置至少默认的 OIDC 客户端。这可以通过已添加到您的应用程序中的环境变量完成,或通过更新配置文件。您可以配置更多客户端,它们将在 drenso.oidc.client.{name} 下可用,并可以通过使用 OidcClientInterface ${name}OidcClient 自动注入,例如 OidcClientInterface $defaultOidcClient。如果名称与配置的客户端不匹配,则将自动注入默认客户端。

配置示例

drenso_oidc:
    #default_client: default # The default client, will be aliased to OidcClientInterface
    clients:
        default: # The client name, each client will be aliased to its name (for example, $defaultOidcClient)
            # Required OIDC client configuration
            well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
            client_id: '%env(OIDC_CLIENT_ID)%'
            client_secret: '%env(OIDC_CLIENT_SECRET)%'

            # Extra configuration options
            #well_known_parser: ~ # Service id for a custom well-known configuration parser
            #well_known_cache_time: 3600 # Time in seconds, will only be used when symfony/cache is available
            #jwks_cache_time: 3600 # Time in seconds, will only be used when symfony/cache is available
            #token_leeway_seconds: 300 # Leeway time in seconds when validating token validity
            #redirect_route: '/login_check'
            #custom_client_headers: []
            #code_challenge_method: ~ # Code challenge method, can be null, 'S256' or 'plain'
            #disable_nonce: false # Set to true when nonce verification should not be used

        # Add any extra client
        #link: # Will be accessible using $linkOidcClient
            #well_known_url: '%env(LINK_WELL_KNOWN_URL)%'
            #client_id: '%env(LINK_CLIENT_ID)%'
            #client_secret: '%env(LINK_CLIENT_SECRET)%'
用户提供者

您需要更新您的用户提供者以实现来自 OidcUserProviderInterface 的方法。需要实现两个方法

  • ensureUserExists(string $userIdentifier, OidcUserData $userData):实现此方法以使用从传递的 OidcUserData 对象中可用的数据启动新账户。标识符是用户数据中的一个可配置属性,默认为 sub。如果无法启动账户,则由于用户提供者无法检索用户,认证将无法进行。
  • loadOidcUser(string $userIdentifier): UserInterface:实现此方法以根据标识符检索用户。我们使用一个专用方法而不是 Symfony 的默认 loadUserByIdentifier,以便您可以检测登录来源,而无需创建专用用户提供者。如果 OIDC 用户标识符是唯一的,则将到 loadUserByIdentifier 的转发应足够。
防火墙配置

如果您使用的是 Symfony <6,请确保在 security.yaml 中启用新认证管理器

security:
  enable_authenticator_manager: true

在您的防火墙中启用 oidc 监听器,请编辑 security.yml

security:
  firewalls:
    main:
      pattern: ^/
      oidc: ~

对于 oidc 监听器,有几个选项可供选择。

您可以直接在防火墙中的 oidc 监听器下进行配置,例如 user_identifier_property

security:
  firewalls:
    main:
      oidc:
        user_identifier_property: email
开始认证

使用下面的控制器示例将用户转发到 OIDC 服务

  /**
   * This controller forwards the user to the OIDC login
   *
   * @throws \Drenso\OidcBundle\Exception\OidcException
   */
  #[Route('/login_oidc', name: 'login_oidc')]
  #[IsGranted('PUBLIC_ACCESS')]
  public function surfconext(OidcClientInterface $oidcClient): RedirectResponse
  {
    // Redirect to authorization @ OIDC provider
    return $oidcClient->generateAuthorizationRedirect();
  }

您可以为 generateAuthorizationRedirect 方法提供提示、作用域和额外的查询参数。

还可以强制使用“记住我”模式进行重定向。

这就足够了!

用户标识符

默认情况下,此组件使用 sub 属性作为用户标识符,但可以任何检索到的用户数据属性。只需将 user_identifier_property 配置为与 Symfony Property Accessor 兼容的属性路径字符串,即可获取所需值。

请注意,使用基于对象的方法从用户数据中检索属性。

记住我

如果您想启用“记住我”功能,请确保将查询参数 _remember_me=1 添加到用于生成重定向调用的路由(调用 generateAuthorizationRedirect 的那个路由)。

您可以针对每个 OIDC 客户端覆盖 _remember_me 参数。只需在客户端配置中更新 remember_me_parameter 的值。

最后,确保已启用 Symfony 的“记住我”认证器,并在 security.yaml 中将 oidc 认证器的 enable_remember_me 选项设置为 true。

用户认证后,您将看到 REMEMBERME 糖果。您可以通过删除 PHPSESSID 糖果来检查“记住我”功能是否正常工作。

注销

如果 Identity Provider 的 end_session_endpoint 参数存在于 .well-known 端点中,则可以通过启用“注销”功能来启用“注销”。

由于在使用单点登录时注销功能本身存在根本性错误,因此该选项默认禁用。这是因为注销身份提供者(例如:Azure、Facebook 等)无法保证用户已从使用相同身份提供者认证的任何其他服务中注销。

如果您想启用“注销”支持,只需将 enable_end_session_listener: true 添加到防火墙配置中的 oidc 监听器。它仅在您启用了默认的 Symfony logout: true 设置时才能正常工作。

默认情况下,监听器会将注销的 target_path 传递给 OpenID 提供者,因此用户在注销后会重定向回您的应用程序。如果您不希望这样做,并且希望用户留在 OpenID 提供者的注销确认页上,请启用 use_logout_target_path: false 设置。

示例:默认注销路径

security:
  firewalls:
    main:
      logout: true
      oidc:
        enable_end_session_listener: true

示例:自定义注销目标路径

security:
  firewalls:
    main:
      logout:
        target: /my_custom_target_path
      oidc:
        enable_end_session_listener: true

示例:禁用重定向到注销 target_path

这将使用户在注销后留在 OpenID 提供者上。

security:
  firewalls:
    main:
      logout: true
      oidc:
        enable_end_session_listener: true
        use_logout_target_path: false

客户端定位器

如果您出于某种原因配置了多个 OIDC 客户端并需要动态检索它们,您可以使用 OidcClientLocator

  public function surfconext(OidcClientLocator $clientLocator): RedirectResponse
  {
    return $clientLocator->getClient('your_client_id')->generateAuthorizationRedirect();
  }

当请求的客户端未找到时,定位器会抛出 OidcClientNotFoundException。在没有参数调用时,它将返回配置的默认客户端。

宽容度

此组件在验证访问令牌时使用 300 秒的宽容度。此值可以通过 token_leeway_seconds 客户端选项进行配置。

缓存

当您的项目中可用的 symfony/cache 时,此库将自动缓存已知和 jwks 结果。默认情况下,它将缓存 3600 秒。

您可以通过将 null 传递给 well_known_cache_timejwks_cache_time 客户端选项来分别禁用缓存。

刷新令牌

目前,本捆绑包提供的防火墙实现不提供刷新令牌(因为它不应该有必要)。但是,如果您需要自行刷新令牌以满足您的实现,您可以在 OidcClientInterface 上使用 refreshTokens 方法!

额外的令牌声明验证

如果您需要验证额外的令牌声明,您可以创建一个实现了 OidcTokenConstraintProviderInterface 的服务,并将其服务 ID 添加到您选择的 OIDC 客户端。

示例配置

drenso_oidc:
    clients:
        default:
            additional_token_constraints_provider: App\Security\AdditionalTokenConstraintProvider

示例约束提供者

namespace App\Security;

use App\Security\Constraint\HasAudienceContaining;
use Drenso\OidcBundle\Enum\OidcTokenType;
use Drenso\OidcBundle\OidcTokenConstraintProviderInterface;

class AdditionalTokenConstraintProvider implements OidcTokenConstraintProviderInterface
{
    public function getAdditionalConstraints(OidcTokenType $tokenType): array
    {
        if (OidcTokenType::ID === $tokenType) {
            return [
                new HasAudienceContaining('abc123'),
            ];
        }

        if (OidcTokenType::ACCESS === $tokenType) {
            return [
                new HasAudienceContaining('def456'),
            ];
        }

        return [];
    }
}

解析已知信息

一些提供者返回不正确或不完整的已知信息。您可以通过将 well_known_parser 设置为实现 OidcWellKnownParserInterface 的服务 ID 来为 OidcClient 配置自定义的已知信息解析器。

OAuth 2.0 令牌交换 RFC 8693

此捆绑包支持令牌交换:您可以使用 OidcClient 上的 exchangeTokens 来执行此操作。这是在 #66 中添加的,其中还包含有关此过程的一些背景信息。

已知用法

使用此捆绑包的开源项目的列表

  • Zitadel 的 example-symfony-oidc:一个模板仓库,包含基本的 OIDC 认证、用户模型、角色和示例页面。