# 连接 OIDC 身份源

# 步骤

# 在你的 OIDC 服务商处创建一个 OIDC Provider

你可以选择任意 OIDC 服务商,具体的创建因服务商的不同而有所不同,这里我们以 AuthingOIDC Provider 为例创建一个 OIDC Provider:

应用 - 应用列表 页面点击右上角的创建按钮创建应用,请确保选择的协议类型为 OIDC:

创建完成之后,你可以在应用详情页面看到该 OIDC 应用的 App ID (即 clientId) 和 App Secret (即 clientSecret),以及 Issuer 地址:

这三项在之后在 Authing 创建 OIDC IdP 连接的时候会用到 。

同时,请将 https://core.authing.cn/connection/oidc/callback 加入你的 OIDC IdP 的允许回调链接里面:

# 在 Authing 控制台创建一个 OIDC IdP 连接

应用控制台 > 连接身份源 > 企业身份源 页面点击右上角的创建按钮创建新的 OIDC 连接:

以下参数的示例如下:

  • 连接标志符: 该连接的唯一标志,在用户池内需保持唯一。
  • 显示名称: 如果设置,Authing 登录表单将会显示一个 "使用 {displayName} 登录" 的按钮。
  • Logo URL: 如果设置,Authing 登录表单将在 "使用 {displayName} 登录" 的按钮上显示此图标,该图标会展示为 20 * 20。
  • Issuer URL: 你想要连接的 OpenID Connect provider 的 Issuer URL
  • Client ID: 你的 OpenID Connect provider 的 Client ID
  • Callback URL: 你需要将此 OIDC IdP 的回调链接设置为 https://core.authing.cn/connections/oidc/callback ,请查看你的 OIDC IdP 的文档说明。

点击创建按钮完成创建。

# 选择适合你的连接模式

连接 OIDC 身份源分为两种模式:

  • Front Channel: 这种模式下,用户信息的交换会全部在浏览器前端完成,会使用 response_mode=form_postresponse_type=id_token 模式,请确保你的 OIDC 应用打开了 implicit 模式,并且返回类型勾选上了 id_token

  • Back Channel: 这种模式下,用户信息的交换会在 Authing 的服务器进行,会使用 response_type=code 授权码模式,所以需要提供你 OIDC 应用的密钥。

你可以根据你的需要选择其中一种模式。

# 使用 Authing 登录表单测试此连接

选择某个应用,点击体验:

可以看到在该表单的最下方多了一个 使用 xxx 登录的按钮,这个就是你刚刚配置的 OIDC 连接:

点击该按钮,浏览器会弹出一个新的窗口到对方 OIDC IdP 的登录页面。由于这里我们使用的是 Authing 的 OIDC 身份源,所以我们又弹出来一个 Authing 的登录表单:

以该 OIDC IdP 支持的任意登录方式完成登录(这里我们使用的是 test@authing.cn 这个账号):

之后该浏览器窗口将会被关闭,回到 Authing 的登录表单。同时可以看到该用户被同步到 Authing 用户池了:

# 使用 API 接口测试此连接

如果你希望使用自己的登录页面来完成 OIDC 身份源连接,你可以通过调用 API 来手动完成:

# POST start-interaction

POST
https://core.authing.cn/api/v2/connections/oidc/start-interaction

当用户池从第三方的 OIDC IdP 跳转回 Authing 服务器的时候,Authing 会通过回调参数中的 state 判断目标用户池,所以需要先调用此接口将 state 和用户池做一个关联。

Body Paramter
state
REQUIRED
string

随机字符串,需要作为后续 OIDC 请求的 state

userPoolId
REQUIRED
string

用户池 ID

returnTo
REQUIRED
string

回调链接

200: OK
{
    code: 200,
    message: "ok"
}

# 发起对 OIDC IdP 的登录请求

这一步是在调用第三方 OIDC IdP 的接口,不同的 OIDC IdP 调用方式可能会有差异,这里以 Authing 的 OIDC IdP 为例。需要注意的一点是发起登录请求时候的 state 需要和第一步的 state 保持一致。

GET
https://<你的应用域名>.authing.cn/oidc/auth

拼接一个链接并让终端用户在浏览器中访问,发起 OIDC 授权登录请求。

发起授权需要拼接一个用来授权的 URL,并让终端用户在浏览器中访问,具体参数如下:

Query Parameters
client_id
REQUIRED
string

应用 ID。

redirect_uri
REQUIRED
string

回调链接,用户在 OP 认证成功后,OP 会将授权码以 URL query 的形式发送到这个地址。这个值必须出现在控制台配置的回调地址中,否则 OP 不允许向该地址回调。

scope
REQUIRED
string

需要请求的权限,必须包含 openid。如果需要获取手机号email 需要包含 phone email;如果需要 refresh_token 需要包含 offline_access。多个 scope 请用空格分隔id_token 解码后的内容中会包含这些 scope 对应的用户信息相关的字段。

response_type
REQUIRED
string

返回类型,可以为 code, id_token, id_token token, code id_token, code token, code id_token token。登录成功后,指定 OP 要返回哪些信息,如果包含 code,OP 会返回授权码 code,如果包含 id_token OP 会返回用户的 id_token,如果包含 token,OP 会返回用户的 access_token。

prompt
OPTIONAL
string

可以为 none,login,consent 或 select_account,指定 OP 与 End-User 的交互方式,如需 refresh_token必须为 consent

state
REQUIRED
string

一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击。这里的 state 需要和第一步的 state 保持一致。

nonce
OPTIONAL
string

一个随机字符串,用于防范 Replay 攻击。

# 接收用户信息

上一步用户同意授权之后,会先跳转到 Authing 服务器,之后 Authing 会携带用户信息跳转到开发者在第一步接口传入的 returnTo 参数 ,并附带以下 Get 请求参数:

参数 说明
code 错误或成功代码,200 为成功,非 200 为失败
message 成功或错误信息
data userInfo,若 code 为非 200 不返回此参数

部分浏览器和 Web Server 在 URL 过长的情况下有可能出现 404,如 ASP.NET,这个时候需要修改一下配置,具体方式请见这个 StackOverflow 回答 (opens new window)

以下是使用 JavaScript 从 URL 参数中获取用户数据的代码:

// 获取 URL 参数
function getQueryString(name) {
  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  var r = window.location.search.substr(1).match(reg);
  if (r != null) {
    return unescape(r[2]);
  }
  return null;
}

// 将 Code 转为 Int 类型,方便判断
const code = parseInt(getQueryString("code"));

if (code !== 200) {
  // 出错了
  const errorMsg = getQueryString("message");
  // 展示 errorMsg 给用户或执行其他业务 ...
} else {
  const userInfo = getQueryString("data");

  // 将 token 存储到 localStorage
  // 建议在之后的请求中附带 Token,并由后端验证 Token 合法性
  localStorage.setItem("token", userInfo.token);
}

# 完成接入

获取到用户信息之后,你可以得到登录凭证 token,你可以在后续的 API 请求中携带上此 token, 然后在后端接口中根据此 token 区分不同用户,详情请见验证 token