本文档介绍如何在 DiscourseConnect 提供方网站上创建链接,这些链接可以将用户登录到 Discourse 并将他们重定向到特定的 Discourse URL。
所需用户级别:管理员
使用 DiscourseConnect 的网站可以在其 DiscourseConnect 提供方网站上添加链接,这些链接可以登录 Discourse 用户并将他们重定向到特定的 Discourse URL。这是通过创建指向 /session/sso 路由的链接来实现的,这些链接设置了 return_path 参数,指向您希望用户最终到达的 Discourse 页面路径。
链接的 href 属性应采用以下格式,将您希望用户最终到达的路径替换为 <相对路径>:
https://forum.example.com/session/sso?return_path=<相对路径>
一个将用户登录并将其重定向到 Discourse 网站主页的示例锚点标签:
<a href="https://forum.example.com/session/sso?return_path=/">社区</a>
一个将用户登录并将其重定向到“热门话题”页面的示例锚点标签:
<a href="https://forum.example.com/session/sso?return_path=/top">热门话题</a>
return_path 在 Discourse 上的存储方式
Discourse 将 return_path 参数的值存储在服务器会话中,其键是用户访问 /session/sso 路由时生成的 SSO 随机数(nonce)。在 DiscourseConnect 身份验证过程结束时,Discourse 会使用该随机数查找 return_path 并将用户重定向到该路径。
使已认证用户体验无缝化
当用户访问 Discourse 的 /session/sso 路由时,他们将被重定向到由 discourse connect url 站点设置定义的 URL。然后,DiscourseConnect 提供方将以与用户点击 Discourse 登录 按钮时相同的方式处理身份验证过程。
为了让已经登录身份验证提供方网站的用户获得无缝体验,身份验证提供方的 DiscourseConnect 代码需要检查用户是否已登录。如果用户未登录,则引导他们完成身份验证提供方的登录流程。如果用户已登录,则跳过身份验证提供方网站上的登录流程。
这是一个带注释的示例,使用了 WP Discourse 插件 中的代码。它演示了如何区别对待已认证用户和未认证用户:
public function sso_parse_request( $wp ) {
// 检查插件选项中是否启用了单点登录 (SSO)
if ( empty( $this->options['enable-sso'] ) ) {
return null;
}
// 在继续 SSO 之前处理任何登出请求
$this->handle_logout_request();
// 检查查询变量中是否存在 'sso' 和 'sig' 参数
if ( array_key_exists( 'sso', $wp->query_vars ) && array_key_exists( 'sig', $wp->query_vars ) ) {
// 清理 'sso' 有效负载和签名,以确保它们安全可用
$payload = sanitize_text_field( $wp->query_vars['sso'] );
$sig = sanitize_text_field( $wp->query_vars['sig'] );
// 如果用户未登录 WordPress,则重定向到登录页面
// 这确保了没有活动会话的用户首先被提示登录 WordPress
if ( ! is_user_logged_in() ) {
// 构建一个 URL,用于在登录后重定向回来
$redirect = add_query_arg( $payload, $sig );
// 生成带有重定向参数的 WordPress 登录 URL
$login = wp_login_url( esc_url_raw( $redirect ) );
// 在重定向到登录页面之前触发一个动作(用于记录或自定义操作是可选的)
do_action( 'wpdc_sso_before_login_redirect', $redirect, $login );
// 重定向到 WordPress 登录页面
return $this->redirect_to( $login );
} else {
// 如果用户已在 WordPress 中通过身份验证,则绕过登录流程
// 并继续验证 SSO 有效负载和签名。
$sso_secret = $this->options['sso-secret'];
$sso = new SSO( $sso_secret );
// 使用 SSO 密钥验证有效负载和签名
if ( ! ( $sso->validate( $payload, $sig ) ) ) {
// 处理无效的 SSO 请求
return $this->handle_error( 'parse_request.invalid_sso' );
}
// 获取当前已登录的 WordPress 用户
$current_user = wp_get_current_user();
// 使用已登录用户的数据准备 SSO 参数
$params = $this->get_sso_params( $current_user );
try {
// 从有效负载生成一个随机数并构建 SSO 登录字符串
$params['nonce'] = $sso->get_nonce( $payload );
$q = $sso->build_login_string( $params );
} catch ( \Exception $e ) {
// 如果 SSO 参数生成出现问题,则处理异常
return $this->handle_error( 'parse_request.invalid_sso_params', array( 'message' => esc_html( $e->getMessage() ) ) );
}
// 在将用户重定向以进行 SSO 登录之前触发一个动作(对记录很有用)
do_action( 'wpdc_sso_provider_before_sso_redirect', $current_user->ID, $current_user );
// 如果启用了详细的 SSO 日志记录,则记录 SSO 成功
if ( ! empty( $this->options['verbose-sso-logs'] ) ) {
$this->logger->info( 'parse_request.success', array( 'user_id' => $current_user->ID ) );
}
// 将已认证用户重定向到带有 SSO 登录字符串的 DiscourseConnect 登录 URL
return $this->redirect_to( $this->options['url'] . '/session/sso_login?' . $q );
}
}
// 如果请求中未找到 SSO 参数,则返回 null
return null;
}
将返回路径设置为非 Discourse URL
Discourse 允许您登录用户并将其重定向到非 Discourse URL。请注意,要使此功能正常工作,您需要在 discourse connect allowed redirect domains 站点设置中添加该域名。默认情况下,此设置为空白,这会阻止重定向到非 Discourse URL。您也可以使用 * 作为通配符来允许所有域名。如果启用此设置,请确保在 return_path 参数中使用绝对 URL,以指向您希望用户转到的任何非 Discourse URL。