如何配置 SSO 提供商
Strapi 上的 单点登录 (SSO) 允许你为 Strapi 管理面板配置额外的登录和注册方法。
- 要在应用上配置 SSO,你需要一个 EnterpriseThis feature is available with an Enterprise plan. 计划或 SSOThis feature is available with the SSO add-on. 插件。
- 确保 Strapi 是你可以通过你的提供商访问的应用之一。例如,对于 Microsoft(Azure)Active Directory,你必须首先请具有相应权限的人将 Strapi 添加到允许的应用列表中。有关详细信息,请参阅你的提供商文档。
- 目前无法将唯一的 SSO 提供商与用于 Strapi 账户的电子邮件地址关联,这意味着无法将对 Strapi 账户的访问限制为仅一个 SSO 提供商。有关更多信息以及解决此问题的替代方法,请参见 please refer to the dedicated GitHub issue。
- 使用 SSO 时,目前无法在完全不同的不相关域上部署管理和后端。
正在访问配置
🌐 Accessing the configuration
SSO 配置保存在 /config/admin 文件中。
🌐 The SSO configuration lives in the /config/admin file.
提供者的配置应以数组形式在管理面板的 auth.providers 路径中编写 提供者配置:
🌐 The providers' configuration should be written in the auth.providers path of the admin panel as an array of provider configurations:
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
auth: {
providers: [], // The providers' configuration lives there
},
});
export default ({ env }) => ({
// ...
auth: {
providers: [], // The providers' configuration lives there
},
});
设置提供程序配置
🌐 Setting up provider configuration
下面文档的部分内容假设在 Strapi 和你的身份提供者中已经完成了一些步骤。如果跳过这些步骤,登录按钮可能会出现在 Strapi 登录页面上,但流程会以重定向或“无效客户端”错误失败。请确保在继续阅读文档的其余部分之前完成检查清单中的所有步骤。
🌐 Parts of the documentation below assume that some steps have been done previously both in Strapi and in your identity provider. If these steps are skipped, the login button might appear on the Strapi login page but the flow will fail with a redirect or "invalid client" error. Make sure to follow all the steps of the checklist before moving onto the rest of the documentation.
提供者的配置是一个使用以下属性构建的 JavaScript 对象:
🌐 A provider's configuration is a JavaScript object built with the following properties:
| 名称 | 是否必填 | 类型 | 描述 ||------------------|----------|----------|------------------------------------------------------------------------------------------------------------------------|| uid | 是 | 字符串 | 策略的 UID。它必须与策略的名称匹配。 || displayName | 是 | 字符串 | 在登录页面上引用提供者时使用的名称。 || createStrategy | 是 | 函数 | 一个工厂函数,用于创建并返回针对你的提供者的新 Passport 策略。以 strapi 实例作为参数。 || icon | 否 | 字符串 | 一个图片 URL。如果指定,它将在登录页面上替换 displayName。 |
uid 属性是每个策略的唯一标识符,通常可以在策略的包中找到。如果你不确定它指的是什么,请联系策略的维护者。
🌐 The uid property is the unique identifier of each strategy and is generally found in the strategy's package. If you are not sure of what it refers to, please contact the maintainer of the strategy.
显示服务提供商标志
🌐 Displaying providers logos
默认情况下,Strapi 的安全策略不允许从外部 URL 加载图片,因此提供商徽标不会显示在管理面板的登录屏幕上,除非通过中间件配置添加安全例外,如下例所示:
🌐 By default, Strapi security policy does not allow loading images from external URLs, so provider logos will not show up on the login screen of the admin panel unless a security exception is added through middlewares configuration, as in the following example:
- JavaScript
- TypeScript
module.exports = [
// ...
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'dl.airtable.com',
'www.okta.com', // Base URL of the provider's logo
],
'media-src': [
"'self'",
'data:',
'blob:',
'dl.airtable.com',
'www.okta.com', // Base URL of the provider's logo
],
upgradeInsecureRequests: null,
},
},
},
},
// ...
]
export default [
// ...
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'dl.airtable.com',
'www.okta.com', // Base URL of the provider's logo
],
'media-src': [
"'self'",
'data:',
'blob:',
'dl.airtable.com',
'www.okta.com', // Base URL of the provider's logo
],
upgradeInsecureRequests: null,
},
},
},
},
// ...
]
为Cookies设置通用域
🌐 Setting common domain for cookies
当将管理面板部署到不同的位置或不同的子域时,需要进行额外的配置来设置 cookie 的公共域。这是为了确保 cookie 可以在各个域之间共享。
🌐 When deploying the admin panel to a different location or on a different subdomain, an additional configuration is required to set the common domain for the cookies. This is required to ensure the cookies are shared across the domains.
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
auth: {
domain: env("ADMIN_SSO_DOMAIN", ".test.example.com"),
providers: [
// ...
],
},
url: env("ADMIN_URL", "http://admin.test.example.com"),
// ...
});
export default ({ env }) => ({
auth: {
domain: env("ADMIN_SSO_DOMAIN", ".test.example.com"),
providers: [
// ...
],
},
url: env("ADMIN_URL", "http://admin.test.example.com"),
// ...
});
createStrategy 工厂
🌐 The createStrategy Factory
通行证策略通常通过使用两个参数实例化来构建:配置对象和验证函数。
🌐 A passport strategy is usually built by instantiating it using 2 parameters: the configuration object, and the verify function.
配置对象
🌐 Configuration object
配置对象取决于策略需求,但通常要求在提供者端建立连接后重定向到回调 URL。
🌐 The configuration object depends on the strategy needs, but often asks for a callback URL to be redirected to once the connection has been made on the provider side.
可以使用 getStrategyCallbackURL 方法为你的提供者生成一个特定的回调 URL。这个 URL 也需要在提供者端进行填写,以允许从该 URL 进行重定向。
🌐 A specific callback URL can be generated for your provider using the getStrategyCallbackURL method. This URL also needs to be written on the provider side in order to allow redirection from it.
回调 URL 的格式如下:/admin/connect/<provider_uid>。
🌐 The format of the callback URL is the following: /admin/connect/<provider_uid>.
strapi.admin.services.passport.getStrategyCallbackURL 是一个 Strapi 帮助工具,你可以用它来获取特定提供者的回调 URL。它以提供者名称作为参数,并返回一个 URL。
如果需要,你还可以在此处放置 OAuth2 应用的客户端 ID 和密钥。
🌐 If needed, this is also where you will put your client ID and secret key for your OAuth2 application.
验证功能
🌐 Verify function
验证函数在这里用作中间件,允许用户对从提供者 API 返回的数据进行转换和额外处理。
🌐 The verify function is used here as a middleware allowing the user to transform and make extra processing on the data returned from the provider API.
此函数总是将 done 方法作为最后一个参数,该方法用于将所需数据传输到 SSO 的 Strapi 层。
🌐 This function always takes a done method as last parameter which is used to transfer needed data to the Strapi layer of SSO.
它的标识如下:void done(error: any, data: object);,并且遵循以下规则:
🌐 Its signature is the following: void done(error: any, data: object); and it follows the following rules:
- 如果
error没有设置为null,则发送的数据将被忽略,并且控制器会抛出错误。 - 如果 SSO 的自动注册功能被禁用,那么
data对象只需要由一个email属性组成。 - 如果 启用了 SSO 的自动注册功能,那么你将需要在
data对象中定义(除了email之外)username属性,或者同时定义firstname和lastname。
添加提供者
🌐 Adding a provider
添加新的提供者意味着为管理员添加新的登录方式。
🌐 Adding a new provider means adding a new way for your administrators to log-in.
Strapi 使用 Passport.js,这使得可以选择大量提供程序。因此,任何不需要额外自定义数据的有效通行证策略都应适用于 Strapi。
像 ldapauth 这样的策略不能开箱使用,因为它们需要从管理面板发送额外的数据。如果你想向你的应用添加 LDAP 提供程序,你需要编写一个 custom strategy。你也可以使用像 Okta 和 Auth0 这样的服务作为桥接服务。
配置提供程序
🌐 Configuring the provider
要配置提供程序,请按照以下步骤操作:
🌐 To configure a provider, follow the procedure below:
- 确保从已安装的软件包或本地文件将策略导入管理配置文件中。
- 在你的管理员面板配置中向
auth.providers数组添加一个与上面提供的格式匹配的新项目。 - 使用
yarn build && yarn develop或npm run build && npm run develop重建并重启你的应用。提供者应该会出现在你的管理员登录页面上。
提供者配置示例
🌐 Provider configuration examples
以下示例显示如何为最常见的提供商配置 SSO:
🌐 The following examples show how SSO is configured for the most common providers:
谷歌
学习如何使用 Google 和 Strapi 配置 SSO。
GitHub
了解如何使用 GitHub 和 Strapi 配置单点登录 (SSO)。
Discord
了解如何配置 Discord 和 Strapi 的单点登录 (SSO)。
微软
了解如何使用 Microsoft 和 Strapi 配置 SSO。
Keycloak
了解如何使用 Keycloak 和 Strapi 配置单点登录 (SSO)。
okta
了解如何使用 Okta 和 Strapi 配置单点登录 (SSO)。
执行高级定制
🌐 Performing advanced customization
管理面板网址
🌐 Admin panel URL
如果管理面板位于与 Strapi 服务器不同的主机/端口上,则需要更新管理面板 URL:在 the /config/admin file 中更新 url 键。
🌐 If the administration panel lives on a host/port different from the Strapi server, the admin panel URL needs to be updated: Update the url key in the /config/admin file.
自定义逻辑
🌐 Custom logic
在某些情况下,你需要为连接工作流程编写额外的逻辑,例如:
🌐 In some scenarios, you will want to write additional logic for your connection workflow such as:
- 限制特定域的连接和注册
- 连接尝试时触发操作
- 添加分析
最简单的方法是插入策略的验证函数并编写一些代码。
🌐 The easiest way to do so is to plug into the verify function of your strategy and write some code.
例如,如果你只想允许拥有官方 strapi.io 邮箱地址的人,你可以像下面这样实例化你的策略:
🌐 For example, if you want to allow only people with an official strapi.io email address, you can instantiate your strategy like follows:
- JavaScript
- TypeScript
const strategyInstance = new Strategy(configuration, ({ email, username }, done) => {
// If the email ends with @strapi.io
if (email.endsWith('@strapi.io')) {
// then we continue with the data given by the provider
return done(null, { email, username });
}
// Otherwise, we continue by sending an error to the done function
done(new Error('Forbidden email address'));
});
const strategyInstance = new Strategy(configuration, ({ email, username }, done) => {
// If the email ends with @strapi.io
if (email.endsWith('@strapi.io')) {
// then we continue with the data given by the provider
return done(null, { email, username });
}
// Otherwise, we continue by sending an error to the done function
done(new Error('Forbidden email address'));
});
身份验证事件
🌐 Authentication events
SSO 功能添加了一个新的身份验证事件:onSSOAutoRegistration