术语
End-User
:终端用户,也可以理解为使用你软件的人
AP(Authentication Provider)
: Authing 服务器
P.S. 文档中出现的 testapp.authing.cn
和 example.authing.cn
两个域名是可以在控制台配置的二级域名。
在 Authing 中创建一个应用
使用 OIDC 需要先注册一个 Authing 账号 并新建一个应用 。
创建 OIDC 应用
在完成了 Authing 应用的创建后相当于你拥有了一个用户池,接下来需要创建一个 OIDC 应用,这样你可以在其他第三方软件中读取用户池中的用户数据,其你给参考:
OIDC 的基本流程
登录成功后回调到开发者配置好的 redirect_uri 中并附带参数
如果返回类型是 code,那么开发者需要在后端使用 code 和 secret(用户创建完 OIDC 应用后会得到)换取 access_token
如果返回类型是 id_token token,那么在用户登录成功后的回调 URI 中会直接附带 id_token 和 access_token
使用 access_token 可以换取用户信息(userInfo)
如果你想直观的体验 OIDC 认证流程,请点击这里查看我们提供的示例 或点击这里可视化的理解 OIDC 。
如果你对如何在后端处理 OIDC 有困惑,请参考 Github 上的示例代码:oidc-demo 。
使用授权码模式(Authorization Code Flow)
这个小节介绍如何使用 code (response_type 为 code)换取 access_token(access_token 可用来换取用户信息)。
发起授权
发起授权需要拼接一个用来授权的 URL,具体参数如下:
在控制台配置的 OIDC 回调 url 其中的一个值
一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击
假设你创建了一个域名为 testapp
的 OIDC 应用,那么授权网址是:
Copy GET https://testapp.authing.cn/oauth/oidc/auth?client_id=5c9b079883e333d55a101082&redirect_uri=https://www.example.cn/example&scope=openid profile&response_type=code&state=jacket
用户登录
上一个请求验证通过后会重定向到 Authing 提供的登录框页面,此时用户需要输入他的用户名和密码进行登录。
此时 Authing 会验证此用户是否合法,如果合法则会跳到用户配置好的 redirect_uri 中并附带 code 参数。
使用 code 换取 token
如果你在控制台配置 OIDC 时,换取 token 方式设置的为 client_secret_post
,那么按照下面这种方法换取 token:
Copy POST https://testapp.authing.cn/oauth/oidc/token
body 参数
授权码,从 redirect_uri 中可直接读取
在控制台配置的 OIDC 回调 url 其中的一个值
授权类型,此处填写为 authorization_code
如果你在控制台配置 OIDC 时,换取 token 方式设置的为 none
,那么换取 token 时无需传递 client_secret,其他参数和上表一样。
如果你在控制台配置 OIDC 时,换取 token 方式设置的为 client_secret_basic
,那么按照下面这种方法换取 token
P.S. client_secret_basic
是使用 HTTP Basic authentication 模式进行认证。
Copy POST https://testapp.authing.cn/oauth/oidc/token
请求头
Copy Content-Type: application/x-www-form-urlencoded
Authorization: Basic NWNhNzY1ZTM5MzE5NGQ1ODkxZGIxOTI3OmJmNGQ0ZTI4ZTg4NWQ4NjBlZWM5YmIzNzEwYjAyMDY1
其中 Basic<空格>
后的值为 <client_id>:<client_secret>
的 base64 值。
body 参数
在控制台配置的 OIDC 回调 url 其中的一个值
授权类型,此处填写 authorization_code
其他 Token 换取方式
如果你想了解其他换取 Token 的方式,请参考 OIDC 规范 。
返回示例
Copy {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJ4R01uczd5cmNFckxiakNRVW9US1MiLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ1Mzc4NjksImV4cCI6MTU1NDU0MTQ2OSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBvZmZsaW5lX2FjY2VzcyBwaG9uZSBlbWFpbCIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.wX05OAgYuXeYM7zCxhrkvTO_taqxrCTG_L2ImDmQjMml6E3GXjYA9EFK0NfWquUI2mdSMAqohX-ndffN0fa5cChdcMJEm3XS9tt6-_zzhoOojK-q9MHF7huZg4O1587xhSofxs-KS7BeYxEHKn_10tAkjEIo9QtYUE7zD7JXwGUsvfMMjOqEVW6KuY3ZOmIq_ncKlB4jvbdrduxy1pbky_kvzHWlE9El_N5qveQXyuvNZVMSIEpw8_y5iSxPxKfrVwGY7hBaF40Oph-d2PO7AzKvxEVMamzLvMGBMaRAP_WttBPAUSqTU5uMXwMafryhGdIcQVsDPcGNgMX6E1jzLA",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjIyMTIxIiwiYXRfaGFzaCI6Ik5kbW9iZVBZOEFFaWQ2T216MzIyOXciLCJzaWQiOiI1ODM2NzllNC1lYWM5LTRjNDEtOGQxMS1jZWFkMmE5OWQzZWIiLCJhdWQiOiI1Y2E3NjVlMzkzMTk0ZDU4OTFkYjE5MjciLCJleHAiOjE1NTQ1NDE0NjksImlhdCI6MTU1NDUzNzg2OSwiaXNzIjoiaHR0cHM6Ly9hdXRoaW5nLmNuIn0.IQi5FRHO756e_eAmdAs3OnFMU7QuP-XtrbwCZC1gJntevYJTltEg1CLkG7eVhdi_g5MJV1c0pNZ_xHmwS0R-E4lAXcc1QveYKptnMroKpBWs5mXwoOiqbrjKEmLMaPgRzCOdLiSdoZuQNw_z-gVhFiMNxI055TyFJdXTNtExt1O3KmwqanPNUi6XyW43bUl29v_kAvKgiOB28f3I0fB4EsiZjxp1uxHQBaDeBMSPaRVWQJcIjAJ9JLgkaDt1j7HZ2a1daWZ4HPzifDuDfi6_Ob1ZL40tWEC7xdxHlCEWJ4pUIsDjvScdQsez9aV_xMwumw3X4tgUIxFOCNVEvr73Fg",
"refresh_token": "WPsGJbvpBjqXz6IJIr1UHKyrdVF",
"scope": "openid profile offline_access phone email",
"token_type": "Bearer"
}
验证 access_token 和 id_token 的合法性
OIDC 默认使用 OIDC 应用的 secret 对 token 进行验证(也就是在创建应用时默认选择 HS256
算法)。
如果你使用 javascript
那么可以使用 jsonwebtoken 进行验证:
Copy const jwt = require('jsonwebtoken');
let decoded = jwt.verify(token, <appSecret>);
如果是其他语言,那么你在服务端需要用 app_secret 作为 HS256 签名参数来计算签名和 JWT 中的签名进行对比,伪代码如下:
Copy HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
"1133fd20c14e4cc29b6ecb71fb8eb952"// app_secret
)
如果是 RS256 等非对称加密算法,需要使用公钥验证签名。Authing 将使用私钥进行签名,请使用 Authing 的公钥来验证签名:
Copy -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxRijj2seoesv5K0Z+ymR
K7DSDPxdsM2sGQD2ZVhLjLsxZWJtXUXh7ERdUU6OT3BqYZZf7CLIhN6yyNtTOgfg
pLG9HVJd7ZSKzuy2dS7mo8jD8YRtptAJmNFqw6z8tQp5MNG1ZHqp9isKqJmx/CFY
kRdXBmjjj8PMVSP757pkC3jCq7fsi0drSSg4lIxrSsGzL0++Ra9Du71Qe/ODQKU0
brxaI1OKILtfcVPTHTaheV+0dw4eYkSDtyaLBG3jqsQbdncNg8PCEWchNzdO6aaj
Uq4wbOzy/Ctp399mz0SGKfuC5S8gqAFABFT3DH3UD21ZztQZwFEV2AlvF+bcGEst
cwIDAQAB
-----END PUBLIC KEY-----
将 token 或 id_token 发送到 Authing 提供的 token 验证接口进行验证
在线验证 access_token / id_token 合法性
GET
https://<appDomain>.authing.cn/oauth/oidc/validate_access_token
Authing 提供了接口用于直接在线验证 access_token 或 id_token 的合法性。
Path Parameters
值为 access_token 或 id_token
200 验证 access_token 或 id_token 时会有以下几种返回结果
Copy access_token 或 id_token 合法时的返回结果
{
"state": 1,
"isRevoked": false,
"isDeleted": false,
"_id": "L3qRMJSE5F0tWlon1OnFhywimkp",
"id": "L3qRMJSE5F0tWlon1OnFhywimkp",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1Y2MzMmIyOGQ2ZWJhZTJmMjQwYTliZmQiLCJhdF9oYXNoIjoieWxHa2Y3a1pKZEg2VjRYbUNRMHFGQSIsInNpZCI6IjlhNzk1MDQ0LTM5MTUtNGI3ZS1hZThhLTAwZDc2YmVhMGIwZCIsImF1ZCI6IjVkMDIzYzdiNTY0MjQ2MTIzNGI5YzYyZSIsImV4cCI6MTU2Njg2NjE3NiwiaWF0IjoxNTY2ODYyNTc1LCJpc3MiOiJodHRwczovL29hdXRoLmF1dGhpbmcuY24vb2F1dGgvb2lkYyJ9.ZeaM9_iyNwwedNktJFdlFXyIGGE692MVpW4wbe8xR7A",
"accessTokenExpiresAt": "2019-08-27T00:36:16.000Z",
"appId": "5d023c7b5642461234b9c62e",
"userOrClientId": "5cc32b28d6ebae2f240a9bfd",
"when": "2019-08-26T23:36:15.000Z",
"iss": "https://oauth.authing.cn/oauth/oidc",
"sub": "5cc32b28d6ebae2f240a9bfd",
"aud": "5d023c7b5642461234b9c62e",
"exp": 1566866176000,
"iat": 1566862575000,
"user_id": "5cc32b28d6ebae2f240a9bfd",
"issued_to": "https://sso.authing.cn",
"audience": "5d023c7b5642461234b9c62e",
"expires_in": 3360,
"access_type": "offline"
}
token 签名错误
{
code: 1922,
message: "token 不合法"
}
token 过期
{
code: 1923,
message: "token 过期"
}
发生其他错误
{
code: 1921,
message: "session 不存在"
}
{
code: 1920,
message: "查找 session 发生错误"
}
参考链接
使用 access_token 换取用户信息
开发者在自己的服务中可以使用 access_token 换取用户信息。根据 scope 的不同,这里的返回信息也会有所不同,字段符合 OIDC 规范 ,字段解释请参考用户信息字段含义 。
请求链接 :
Copy GET https://users.authing.cn/oauth/oidc/user/userinfo?access_token=<access_token>
返回示例 :
Copy {
"sub": "<用户在 Authing 的唯一标识>",
"nickname": "Authing",
"name": "张三",
"locale": "en-US"
}
更多字段解释请参考用户信息字段含义 。
刷新 token
刷新 token 请使用 token 接口返回的 refresh_token.
请求链接 :
Copy POST https://example.authing.cn/oauth/oidc/token
其中 Content-Type
需为 application/x-www-form-urlencoded
body 部分携带参数如下表 :
code 换 token 接口返回的 refresh_token。例:WPsGJbvpBjqXz6IJIr1UHKyrdVF
返回示例 :
Copy {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJ4MjlRNnIzWkpndVViWHB5RGR0ZVciLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ2MTI0NjQsImV4cCI6MTU1NDYxNjA2NCwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBvZmZsaW5lX2FjY2VzcyBwaG9uZSBlbWFpbCIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.VgrdtZRCbapS0hCe5BiV-8rUTXd4x-ZMoFPHV5Zh_HCw-OsJoYN0mVwB1UQ0ZkrA4ojpcZ3MrLnKzRC81BgEnfvaInTqXW8qP36TvR-vl7JkVT-ThkBr0Xdilk0hCfWaMbX9qtCjWYT0b9zxDAdkBKygjztZ74TwKbxNI83vdKSj9A6OfwX9MG4k-Q3ZbKAj1fwncBAp2DEsv1Bd_-4y_n_w-2QtbzZf3409UEotKuU_wGLoVE3DLxJFvEtmunbxQOkqxOGS_JaIvFdhpTZ6I3H_DC5KO8xOR2A6nZGFOhYOZZfnr6tmY_EnOIEsnp4glgTCOqHhd1xoBoDcnEmWEA",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjIyMTIxIiwiYXRfaGFzaCI6InVySTYzZ3hyeU01UzNqejRLMmpWeGciLCJzaWQiOiIxOTdlOGExMy0wMzE4LTRkZDEtYjQ3Mi0xZjI0MDk5ZTUzOWYiLCJhdWQiOiI1Y2E3NjVlMzkzMTk0ZDU4OTFkYjE5MjciLCJleHAiOjE1NTQ2MTYwNjQsImlhdCI6MTU1NDYxMjQ2NCwiaXNzIjoiaHR0cHM6Ly9hdXRoaW5nLmNuIn0.wh3kCIGyu7IHvkbqCeu9OHg9mdLg-wSbU-1UBLPcNxl5MeXsGxtxjPyM6aONxLt_ZXfBFNZM7FWfGpV_qGSNmeGp0UYV_bK-N0wgB5ZkTN1O4EMECqy7qCExwK3kjsOa-o0KkkJxxcDkfEJ3Icn2Nr3q5ozMz_3oGJWqSt0KxQaR_rCtjbLV6dIpPL1MTpWElORXjsoKb1RVOHF0Qpfq8iuGVJAw828tq4cyLH9-IkE9TGX2L6dWmPaY1xd0ho0N1mqnWJrqacljrvX8qPTfGAB9-9rDk2EvFrZkFY6O6bKlMqdyX4ktxYMlku4-H74wxOqkQ_ZWlI3SUG_m-DNDWg",
"refresh_token": "wlfsGj5oSm5xmdUV_HqS9FTQpaj",
"scope": "openid profile offline_access phone email",
"token_type": "Bearer"
}
使用隐式流程(Implicit Flow)
隐式流程将不获取 code,直接在回调地址中附带 access_token
和 id_token
。
发起授权
发起授权需要拼接一个用来授权的 URL,具体参数如下:
在控制台配置的 OIDC 回调 url 其中的一个值。启用隐式模式时,控制台配置的所有 redirect_uri 必须都为 https 协议
一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击
一个随机字符串,用于防范 Replay 攻击,implicit 模式下必须填
假设你创建了一个域名为 example
的 OIDC 应用,那么授权网址是:
Copy GET https://example.authing.cn/oauth/oidc/auth?client_id=5ca765e393194d5891db1927&redirect_uri=https://example.com&scope=openid profile&response_type=id_token token&state=jazz&nonce=1831289
获取 id_token 和 access_token
id_token、access_token 会以 url hash 的形式传递,跳转后链接示例:
Copy https://authing.cn/#id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1Y2QwMjZlZjNlZDlmOTRkODBmZTM2YWUiLCJub25jZSI6IjE4MzEyODkiLCJzaWQiOiI4YzgzN2I5My01OTNlLTQzZjctYWMzNC0yYjRmZDU3ZGFhMTciLCJhdF9oYXNoIjoiVFFtbFlEVTVPZGF1Zjl0U0VKdHY5USIsInNfaGFzaCI6Ind3SDNXclV2b0hiSUp5TWVZVHU4bHciLCJhdWQiOiI1ZDAxZTM4OTk4NWY4MWM2YzFkZDMxZGUiLCJleHAiOjE1NjA0MDkzNjgsImlhdCI6MTU2MDQwNTc2OCwiaXNzIjoiaHR0cHM6Ly9vYXV0aC5hdXRoaW5nLmNuL29hdXRoL29pZGMifQ.T9M0s6rk4Teq6VOOBRIElgHK9KyM3q0ZJj2aS0VD_Fw&access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3OE9XcVJNVXJEUXpMMXpHVzVtUWoiLCJzdWIiOiI1Y2QwMjZlZjNlZDlmOTRkODBmZTM2YWUiLCJpc3MiOiJodHRwczovL29hdXRoLmF1dGhpbmcuY24vb2F1dGgvb2lkYyIsImlhdCI6MTU2MDQwNTc2OCwiZXhwIjoxNTYwNDA5MzY4LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIiwiYXVkIjoiNWQwMWUzODk5ODVmODFjNmMxZGQzMWRlIn0.mR0MZDwlZWGRMsAZjQ27sDFFqYoDgZ6WHTK4C7JbML4&expires_in=3600&token_type=Bearer&state=jazz&session_state=26ec053be9f47d68dc430f84b97efb1095469fe10169a9e00ef4092718714b8b
换取用户信息的流程和授权码模式相同。
使用混合模式(Hybrid Flow)
隐式流程将不获取 code,直接在回调地址中附带 code
、access_token
和 id_token
,且都以 URL Hash 的形式传递。
发起授权
发起授权需要拼接一个用来授权的 URL,具体参数如下:
在控制台配置的 OIDC 回调 url 其中的一个值。启用隐式模式时,控制台配置的所有 redirect_uri 必须都为 https 协议
一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击
一个随机字符串,用于防范 Replay 攻击,混合模式下必填
假设你创建了一个域名为 example
的 OIDC 应用,那么授权网址是:
Copy GET https://example.authing.cn/oauth/oidc/auth?client_id=5ca765e393194d5891db1927&redirect_uri=https://example.com&scope=openid profile&response_type=code id_token token&state=jazz&nonce=1831289
跳转后链接示例:
Copy https://example.com/#code=pIY83Jl_bcerNN9Wt57Sq0TAjTr&id_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjE4MzEyODkiLCJzaWQiOiIxOTdlOGExMy0wMzE4LTRkZDEtYjQ3Mi0xZjI0MDk5ZTUzOWYiLCJhdF9oYXNoIjoiUFlXaTFER29jRlotYmlYd0d5WXlpZyIsImNfaGFzaCI6Ik4yUmkyUFpidktYdXRmdGhZbUhrM2ciLCJzX2hhc2giOiJ3d0gzV3JVdm9IYklKeU1lWVR1OGx3IiwiYXVkIjoiNWNhNzY1ZTM5MzE5NGQ1ODkxZGIxOTI3IiwiZXhwIjoxNTU0NjE1NjcyLCJpYXQiOjE1NTQ2MTIwNzIsImlzcyI6Imh0dHBzOi8vYXV0aGluZy5jbiJ9.a--JC_6CyUi0Z7z3DCKT51wJkKT7MmtlVHhrNujhxHCfgQqzqS3wMxVj6oEe_cfjVQNgJ-Xe1oiL8uMAxVN-cM1Ra1JQcavUujua2IxxtG4Nkh84rTukqsrPfuNhNO7MRP6Fa9qIIdKeKkQKyh1zBKE6322zK_ECdfGd2sWdqqXiQyJXg6ODhPZDidsGuluV3bZiAY3brMSMmh6QC99StOP5ZwSKtlRMyYE3MIRWsQ4W2HkHBrk67T_scQ6XN6mdBKi2OZW-E7fXeyVwH-ibWDzlUpmFSaj3a-WbkDe3nfCv8MHj439aJNU-AXfIgLsckvCO5_dJOUWGHg6hemT9bw&access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiIxUzgyaUtSdXFlWW1DUmFrMFl1S0kiLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ2MTIwNzIsImV4cCI6MTU1NDYxNTY3Miwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.tHwxiH5QXXA46Y4mIwcBck3uDArMj5TMGEBAQ8Eeln6oFbwBY3aS5cSV6e3anZDwKZrdgrdFlyj9-Bl1T5V1rNJK-Xz_aFnM6XxyO1jSHcn-6KXGwmz68D50VIHior39cuoj9OXbNCei5RVghjh2cRT3SenYki7UeJBgmfQA6l2aZZpBrn9aphXr9OoPS47T59I0Ynn2yMIYIMDOX7hh8E5oV1hrK3hyjAvp3ghmzyRfj2BlG9rBo1hd_d5E8x6OIzNdvPKXwVASJZRxov2Dx0ma36zxzSObyXgCloUv2KlbmL9-Wj8d3H6FhHC75DLfJYx-uRgNqW7CFKGeRkPjkQ&expires_in=3600&token_type=Bearer&state=jazz&session_state=101666b6b70cfb4406ad9c0c906039de39776140e66e48acdb63ab8acb309701
换取用户信息的流程和授权码模式相同。
退出 SSO
如果你使用了 OAuth、OIDC 或 SAML 实现了单点登录,那么使用户退出登录需要跳转到一个 URL:
https://<你的域名>.authing.cn/login/profile/logout?app_id=<OAuth 应用 ID>&redirect_uri=<退出之后的回调地址>
其中 app_id
和 redirect_uri
都是必填选项,redirect_uri
是退出后你想要返回的地址。
如果你想要在后端退出 SSO,可以自行维护一个 Cookie - Session 的状态,然后设置 Cookie 过期即可。
接下来你可能需要