单点登录(Single Sign On)可用于从独立网站处理 Discourse 用户认证。有关如何实现 DiscourseConnect 的详细信息,请参阅主题:https://meta.discourse.org/t/official-single-sign-on-for-discourse-sso/13045。
问题所在
使用 DiscourseConnect 时,当用户从您的外部网站登录到 Discourse 时,会创建或更新 Discourse 用户。但它无法处理您需要在用户未登录到您网站的情况下创建或更新 Discourse 用户的情况。对于使用 DiscourseConnect 的网站,这些情况应通过向 sync_sso 路由发送经过身份验证的 POST 请求来处理。
如果您正在使用 Discourse API gem,可以使用该 gem 的
sync_sso方法,而无需使用以下代码。有关如何使用该方法的说明,请参阅 示例 目录。
举个例子,假设父站点上将用户添加到了一个群组,而您需要将该用户添加到 Discourse 上对应的群组中,且无需他们先通过 DiscourseConnect 登录。网站和论坛上的群组名称均为 ‘eurorack’。用户的 external_id 为 1,电子邮件为 bob@example.com。以下代码使用 PHP 编写。基本思路可应用于任何编程语言。
设置您的 API 凭据和 SSO 密钥
$api_key = '4fe83002bb5fba8c9a61a65e5b4b0a3cf8233b0e4ccafc85ebd6607abab4651a';
$api_username = 'system';
$discourse_connect_secret = 'jdhb19*Xh3!nu(#k';
设置 SSO 参数
要查看可用的参数,请查看 discourse_connect_base.rb 中的 ACCESSORS 部分。要更新现有用户,您必须包含的参数是 external_id。如果您为尚未存在于 Discourse 上的用户调用 sync_sso,则必须包含 username 和 email 参数。Discourse 将使用 username 和 email 来创建新用户。
要将用户添加到群组,请包含 add_groups 参数。要从群组中移除用户,请包含 remove_groups 参数。这两个参数的值必须设置为以逗号分隔的群组名称字符串。群组名称之间不允许有空格。
有效载荷中包含了
require_activation参数。如果用户在父站点上的电子邮件尚未验证,则应将其设置为true。在PHP中,该参数需要设置为字符串 ‘true’,以避免其被转换为数字1。如果您已验证用户的电子邮件地址,则无需包含此参数。
// 创建 SSO 参数数组。
$sso_params = array(
'external_id' => 1,
'email' => 'bob@example.com',
'username' => 'bob',
'add_groups' => 'eurorack',
'require_activation' => 'true',
);
// 将 SSO 参数转换为 SSO 有效载荷并生成 SSO 签名。
$sso_payload = base64_encode( http_build_query( $sso_params ) );
$sig = hash_hmac( 'sha256', $sso_payload, $discourse_connect_secret );
发送 POST 请求
在此示例中,我将使用 curl,将 user_agent 设置为 ‘WordPress/4.9.4’,并将论坛 URL 设置为 https://forum.example.com。
$url = 'https://forum.example.com/admin/users/sync_sso';
$post_fields = array(
'sso' => $sso_payload,
'sig' => $sig,
);
$headers = array("Content-Type: multipart/form-data;","Api-Key: $api_key","Api-Username: $api_username",);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, 1 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $post_fields ) );
curl_setopt( $ch, CURLOPT_USERAGENT, 'WordPress/4.9.4' );
$result = curl_exec( $ch );
if ( curl_errno( $ch ) !== 0 ) {
// 处理错误,调用 curl_close( $ch ) 并返回。
}
curl_close( $ch );
$discourse_user = json_decode( $result );
更新现有用户
对 sync_sso 路由发出的请求将以与用户通过 DiscourseConnect 登录到网站时相同的方式更新现有用户的属性。这意味着您的站点的 auth overrides 和 discourse connect overrides 站点设置值将被这些请求所尊重。例如,要通过 sync_sso 请求更新现有用户的电子邮件地址,需要启用 auth overrides email 设置。以下是相关设置:
auth overrides emailauth overrides usernameauth overrides namediscourse connect overrides avatardiscourse connect overrides biodiscourse connect overrides groupsdiscourse connect overrides profile backgrounddiscourse connect overrides card backgrounddiscourse connect overrides locationdiscourse connect overrides website
进一步阅读
要了解具体运作情况,请查看 sync_sso 代码、DiscourseConnectBase 的 parse 方法以及 DiscourseConnect 的 lookup_or_create_user 方法。
对于使用 Node.js 的用户,本指南还有一个 JavaScript 版本。