socialiteproviders / saml2
Laravel Socialite 的 SAML2 服务提供者
Requires
- php: ^8.0
- ext-json: *
- litesaml/lightsaml: ^4.0
- socialiteproviders/manager: ^4.4
README
composer require socialiteproviders/saml2
安装与基本使用
请参阅基础安装指南,然后按照以下提供者的具体说明操作。
注意SAML 协议部分。
将配置添加到config/services.php
可以使用以下任何一种方法配置身份提供者。如果您的 IDP 支持它,强烈建议使用元数据 URL,这样在 IDP 端的证书轮换就不会导致任何服务中断。
使用身份提供者元数据 URL
'saml2' => [ 'metadata' => 'https://idp.co/metadata/xml', ],
使用身份提供者元数据 XML 文件
'saml2' => [ 'metadata' => file_get_contents('/path/to/metadata/xml'), ],
提供者将自动选择元数据中的第一个 IdP 描述符。如果您的元数据包含多个描述符,您可以通过同时使用 metadata
和 entityid
配置选项来选择要使用的一个。
使用身份提供者元数据 URL,选择特定的描述符
'saml2' => [ 'metadata' => 'https://idp.co/metadata/xml', 'entityid' => 'http://saml.to/trust', ],
使用证书字符串手动配置身份提供者
'saml2' => [ 'acs' => 'https://idp.co/auth/acs', // (the IDP's 'Assertion Consumer Service' URL. Also known as the assertion callback URL or SAML assertion consumer endpoint) 'entityid' => 'http://saml.to/trust', // (the IDP's globally unique "Entity ID", normally formatted as a URI, but it is not a real URL) 'certificate' => 'MIIC4jCCAcqgAwIBAgIQbDO5YO....', // (the IDP's assertion signing certificate) ],
使用证书文件手动配置身份提供者
'saml2' => [ 'acs' => 'https://idp.co/auth/acs', 'entityid' => 'http://saml.to/trust', 'certificate' => file_get_contents('/path/to/certificate.pem'), ],
添加提供者事件监听器
Laravel 11+
在 Laravel 11 中,默认的 EventServiceProvider
提供者已被移除。取而代之,您可以在 AppServiceProvider
的 boot
方法中使用 Event
门面上的 listen
方法添加监听器。
- 注意:除非您用自己的提供者覆盖它们,否则您不需要为内置的 Socialite 提供者添加任何内容。
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) { $event->extendSocialite('saml2', \SocialiteProviders\Saml2\Provider::class); });
Laravel 10 或以下
配置包的监听器以监听 `SocialiteWasCalled` 事件。在 app/Providers/EventServiceProvider
中的 listen[]
数组中添加该事件。有关详细说明,请参阅基础安装指南。
protected $listen = [ \SocialiteProviders\Manager\SocialiteWasCalled::class => [ // ... other providers \SocialiteProviders\Saml2\Saml2ExtendSocialite::class.'@handle', ], ];
使用方法
现在您应该能够像常规使用 Socialite 一样使用提供者(假设您已安装门面)
要启动身份验证流程
Route::get('/auth/redirect', function () { return Socialite::driver('saml2')->redirect(); });
要接收回调
Route::get('/auth/callback', function () { $user = Socialite::driver('saml2')->user(); });
SAML 协议
为了与 Socialite 和 Laravel 充分兼容,Saml2 提供者默认使用 GET 路由进行身份验证回调。或者在 SAML 术语中,它使用服务提供者断言消费者 URL 上的 HTTP-Redirect
绑定
Route::get('/auth/callback', function () { $user = Socialite::driver('saml2')->user(); });
虽然这与 Socialite 的操作方式一致,但这并不是最常见的 SAML 回调风格,许多身份提供者都不支持它。正常方法是使用 HTTP-POST
绑定,Saml2 也支持它。要使用此方法,只需将您的 Laravel 路由定义为 POST
路由即可
Route::post('/auth/callback', function () { $user = Socialite::driver('saml2')->user(); });
但是,请注意,这与 Laravel 默认在 routes/web.php
文件上执行的 POST
路由的 CSRF 过滤不兼容。为了使此回调风格工作,您可以将此路由定义为 web.php
之外的路由,或者将其添加到您的 VerifyCsrfToken
HTTP 中间件的异常中。
如果您添加了两个路由来支持两种绑定方法,您可以在 config/services.php
中像这样选择默认的一个
'saml2' => [ 'sp_default_binding_method' => \LightSaml\SamlConstants::BINDING_SAML2_HTTP_POST, ],
无状态
提供者支持 SAML2 无请求/身份提供者发起的请求。要使用此技术,必须将 回调 路由设置为无状态的。
Route::get('/auth/callback', function () { $user = Socialite::driver('saml2')->stateless()->user(); });
(注意,这与 标准 Socialite 使用方式不同,其中标记为无状态的 重定向)
单点登出
警告!请注意,SAML2单点登出功能是集中登出的最佳尝试方式。根据当前情况,它需要特殊条件才能工作。您必须将您的会话配置设置为same_site = 'none'
和secure = true
才能使其正常工作,这具有严重的安全影响。在使用此功能之前,请务必理解风险。
您可以通过添加一个GET路由来启用您的服务提供者上的SingleLogoutService,在该路由中,您将登出用户并生成SAML2登出响应
Route::get('/auth/saml2/logout', function () { $response = Socialite::driver('saml2')->logoutResponse(); });
要发布您的服务提供者元数据中的SingleLogoutService,您还必须在config/services.php
中配置路由
'saml2' => [ 'sp_sls' => 'auth/saml2/logout', ],
签名和加密
SAML2支持消息和声明的签名和加密。许多身份提供者要求其中之一或两者都是必需的。要启用此功能,您可以为您的应用程序生成一个证书,并在config/services.php
中提供它
'saml2' => [ 'sp_certificate' => file_get_contents('path/to/sp_saml.crt'), 'sp_private_key' => file_get_contents('path/to/sp_saml.pem'), 'sp_private_key_passphrase' => 'passphrase to your private key, provide it only if you have one', 'sp_sign_assertions' => true, // or false to disable assertion signing ],
sp_private_key_passphrase
是可选的,如果私钥未加密,则不应提供。
始终保护您的私钥,并将其存储在公众无法访问的地方。
使用openssl生成证书和私钥的示例命令
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout sp_saml.pem -out sp_saml.crt
验证
提供者验证声明中的时间戳,包括NotBefore
和NotOnOrAfter
。默认的时钟偏移量是120秒,但这可以作为配置的一部分进行更改
'saml2' => [
'metadata' => 'https://idp.co/metadata/xml',
'validation' => [
'clock_skew' => 30, // Time in seconds
],
],
提供者检查身份提供者永远不会重复一个断言ID。默认情况下,ID会永久记住,但这可以进行配置
'saml2' => [
'metadata' => 'https://idp.co/metadata/xml',
'validation' => [
'repeated_id_ttl' => 365 * 24 * 60 * 60, // Time in seconds, or null to cache forever
],
],
身份提供者元数据
当使用身份提供者的元数据URL时,默认情况下,获取的元数据会缓存24小时。要修改此存活时间值,请使用config/services.php中的'ttl'键
'saml2' => [ 'metadata' => 'https://idp.co/metadata/xml', 'ttl' => 3600, // TTL in seconds ],
要程序化地清除缓存,您可以使用
Socialite::driver('saml2')->clearIdentityProviderMetadataCache();
元数据每24小时重新获取一次,但如果获取失败,则以前获取的元数据将用于接下来的24小时。如果元数据的第一次获取失败,将抛出GuzzleException
。
服务提供者元数据
为了简化在身份提供者端配置Laravel服务提供者的配置,您可以在路由上公开服务提供者的XML元数据
Route::get('/auth/saml2/metadata', function () { return Socialite::driver('saml2')->getServiceProviderMetadata(); });
请注意,您的Laravel服务的断言消费者服务URL已填充在元数据中,因此必须在config/services.php的sp_acs
键中设置,如果它不是Socialite的默认值'/auth/callback'。
例如,如果这是您的回调路由
Route::get('/auth/saml2/callback', function () { $user = Socialite::driver('saml2')->user(); });
则在config/services.php
中应配置ACS路由
'saml2' => [ 'metadata' => 'https://idp.co/metadata/xml', 'sp_acs' => 'auth/saml2/callback', ],
服务提供者的默认实体ID是到'/auth/saml2'(例如 https://your.domain.com/auth/saml2
)的URL,如果需要,可以在config/services.php中手动配置,如下所示
'saml2' => [ 'metadata' => 'https://idp.co/metadata/xml', 'sp_entityid' => 'https://my.domain.com/my/custom/entityid', ],
服务提供者的实体ID和断言消费者URL也可以通过以下方式程序化检索
Socialite::driver('saml2')->getServiceProviderEntityId() Socialite::driver('saml2')->getServiceProviderAssertionConsumerUrl()
您还可以通过在config/services.php中配置它们来在元数据中发布服务提供者的组织和技术支持联系人
'saml2' => [ 'sp_tech_contact_surname' => 'Doe', 'sp_tech_contact_givenname' => 'John', 'sp_tech_contact_email' => 'john.doe@example.com', 'sp_org_lang' => 'en', 'sp_org_name' => 'Example Corporation Ltd.', 'sp_org_display_name' => 'Example Corporation', 'sp_org_url' => 'https://corp.example', ],
如果您想包含此信息,您必须至少配置组织包含的sp_org_name
,以及联系人包含的sp_tech_contact_email
。默认情况下,sp_org_lang
为英文(en
)。
当配置服务提供者证书时,签名和加密证书会自动包含在元数据中。
用户属性和Name ID
根据SAML惯例,由身份提供者发送的"Name ID"用作回调中返回的User
类实例的ID。
来自 'http://schemas.xmlsoap.org/...' 和 'urn:oid:...' 命名空间的已知SAML属性映射到User
类中的name
、email
、first_name
、last_name
和upn
。
由身份提供者返回的所有其他属性存储在User
类的"raw"属性中,可以通过$user->getRaw()
获取。
可以通过在config/services.php
中提供一个部分/完整的自定义映射来扩展/覆盖默认映射。
'saml2' => [ 'attribute_map' => [ // Add mappings as 'mapped_name' => 'saml_attribute' or 'mapped_name' => ['saml_attribute', ...], for example: 'email' => [ \SocialiteProviders\Saml2\OasisAttributeNameUris::MAIL, \LightSaml\ClaimTypes::EMAIL_ADDRESS, ], 'phone' => \SocialiteProviders\Saml2\OasisAttributeNameUris::PHONE, ], ],
整个断言也存储在User
实例中,可以通过$user->getAssertion()
获取。