¶ 成为 OpenID Connect 身份源
本文介绍如何让 Authing 成为 OIDC 身份源,其他系统可以通过 OIDC 协议接入 Authing 作为身份提供商。
OpenID Connect 协议简称 OIDC,是一种轻量、安全的身份认证和授权协议。OIDC 是 OAuth 2.0 协议的超集。
OpenID Connect 协议有以下几种授权模式,分别是
成为 OpenID Connect 身份源后,其他应用可以使用相应模式的流程完成用户的认证与授权。
你可以在这里深入理解 OIDC 协议。
¶ 创建应用
为了让你的应用具备身份认证能力,你需要在 Authing 创建一个应用,名称建议填写你的实际应用项目的名称,进入控制台 > 应用 > 应用列表,点击创建应用:
填写你的应用名称,例如:网络笔记项目,为你的项目指定一个认证地址,将来你的用户会在这个地址完成认证。回调链接填写你的项目后端路由,Authing 会将用户信息(确切地说是一个授权码 code)发送到这个地址。最后点击创建。
¶ 授权码模式
如果你的应用项目有后端服务,能够安全存储密钥,建议使用授权码模式。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,授权模式中勾选 authorization_code
,返回类型中勾选 code
,然后点击保存。
整体上,有以下流程。
- 在你的应用中,让用户访问登录链接,浏览器跳转到 Authing,用户在 Authing 完成认证。
- 浏览器接收到一个从 Authing 服务器发来的授权码。
- 浏览器通过重定向将授权码发送到你的应用后端。
- 你的应用服务将授权码发送到 Authing 获取 AccessToken 和 IdToken,如果需要,还会返回 refresh token。
- 你的应用后端现在知道了用户的身份,后续可以保存用户信息,重定向到前端其他页面,使用 AccessToken 调用资源方的其他 API 等等。
流程图如下:
¶ 授权码 + PKCE 模式
如果你的应用是一个 SPA 前端应用或移动端 App,建议使用授权码 + PKCE 模式来完成用户的认证和授权。授权码 + PKCE 模式适合不能安全存储密钥的场景(例如前端浏览器)。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,授权模式中勾选 authorization_code
,返回类型中勾选 code
,点击保存。在「安全性」卡片中,换取 token 身份验证方式、检验 token 身份验证方式、撤回 token 身份验证方式选择 none
然后点击保存。
整体上,有以下流程。
- 在你的应用中,让用户访问登录链接,浏览器跳转到 Authing,用户在 Authing 完成认证。
- 浏览器接收到一个从 Authing 服务器发来的授权码。
- 浏览器通过重定向将授权码发送到你的应用前端。
- 你的应用将授权码和校验码发送到 Authing 获取 AccessToken 和 IdToken,如果需要,还会返回 Refresh token。
- 你的应用前端现在知道了用户的身份,后续使用 Access token 换取用户信息,重定向到前端其他页面,使用 AccessToken 调用资源方的其他 API 等等。
流程图如下:
¶ 隐式模式
如果你的应用是一个 SPA 前端应用,不具备后端服务,建议使用隐式模式来完成用户的认证和授权。隐式模式适合不能安全存储密钥的场景(例如前端浏览器)。在隐式模式中,应用不需要使用 code 换 token,无需请求 /token
端点,AccessToken 和 IdToken 会直接从认证端点返回。
因为隐式模式用于不能安全存储密钥的场景,所以隐式模式不支持获取 Refresh Token。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,授权模式中勾选 implicit
,返回类型中勾选 id_token token
和 id_token
,然后点击保存。
整体上,有以下流程。
- 在你的应用中,让用户访问登录链接,浏览器跳转到 Authing,用户在 Authing 完成认证。
- Authing 将浏览器重定向到你的应用回调地址,AccessToken 和 IdToken 作为 URL hash 传递。
- 你的应用从 URL 中取出 token。
- 你的应用可以将 AccessToken 与 IdToken 保存,以便后续使用,例如携带 AccessToken 访问资源服务器,携带 IdToken 请求服务端从而服务端能够辨别用户身份。
流程图如下:
¶ 混合模式
在某些场景你可能既希望直接从认证端点获取 token,又能获取授权码 code 用于后续获取 refresh token,建议使用混合模式。在混合模式中,应用会收到 token 与 code。应用可以选择将 code 发送给后端服务,用于从 /token
端点获取用户的 AccessToken、IdToken、refresh token。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,授权模式中勾选 authorization_code
和 implicit
,返回类型中勾选 code id_token token
、code id_token
和 code token
,然后点击保存。
整体上,有以下流程。
- 在你的应用中,让用户访问登录链接,浏览器跳转到 Authing,用户在 Authing 完成认证。
- Authing 将浏览器重定向到你的应用回调地址,code、AccessToken、IdToken 作为 URL hash 传递。
- 你的应用从 URL 中取出 code 和 token。
- 你的应用可以将 AccessToken 与 IdToken 保存,以便后续使用,例如携带 AccessToken 访问资源服务器,携带 IdToken 请求服务端从而服务端能够辨别用户身份。
- 你的应用可以将 code 发送给后端。
- 应用后端可以利用 code 获取用户的 AccessToken、IdToken 以及 refresh token。之后可以保存用户信息,使用 AccessToken 调用资源方的其他 API 等等。
流程图如下:
¶ Client Credentials 模式
Client Credentials 模式用于进行服务器对服务器间的授权(M2M 授权),期间没有用户的参与。你需要创建编程访问账号,并将 AK、SK 密钥对交给你的资源调用方。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,id_token 签名算法
选择 RS256
,授权模式中勾选 client_credentials
然后点击保存。
整体上,有以下流程。
- 资源调用方将他的凭证 AK、SK 以及需要请求的权限 scope 发送到 Authing 授权端点。
- 如果凭证正确,并且调用方具备资源权限,Authing 为其颁发 AccessToken。
流程图如下:
¶ 密码模式
不推荐使用此模式,尽量使用其他模式。只有其他模式都无法解决问题时才会考虑使用密码模式。如果使用密码模式,请确保你的应用代码逻辑非常安全,不会被黑客攻击,否则将会直接泄露用户的账密。一般用于改造集成非常古老的应用,否则绝对不要把它作为你的第一选择。
首先在控制台 > 应用,找到你的应用,进入应用详情,在下方的「授权」卡片中,授权模式中勾选 password
然后点击保存。
整体上,有以下流程。
- 你的应用让用户输入账密信息。
- 你的应用将用户账密发送到 Authing。
- 如果账密正确,Authing 返回 token。
流程图如下:
¶ 刷新 Access Token
刷新 Access Token 需要用到 Refresh Token,你可以在这里学习 Refresh Token 相关的内容。Refresh Token 用于获取新的 Access Token,保持用户登录态。
¶ 获取 Refresh Token
如果你想获取 Refresh Token ,你需要发送请求到 Authing 获取 Refresh Token。
只有授权码模式和密码模式支持 Refresh Token。
下表中展示的授权模式与 Scope 参数组合发送到 Token 端点时,Authing 会返回 Refresh Token。
授权模式 | Scope |
---|---|
refresh_token | offline_access |
password | offline_access |
注意 ⚠️⚠️⚠️:使用授权码模式时必须在请求授权端点(/oidc/auth
) 时携带 scope 参数,值必须包含 offline_access
,还必须携带 prompt 参数,值必须为 consent
。否则 Authing 不会返回任何 Refresh Token。
¶ 在授权码模式中获取 Refresh Token
在使用授权码模式时,首先需要访问授权端点(/oidc/auth
),携带 scope 参数,值必须包含 offline_access
,还必须携带 prompt 参数,值必须为 consent
,获取一个授权码 Code。然后将授权码发送到 Token 端点,Authing 会返回 Access Token、Id Token 和 Refresh Token。查看使用 OIDC 授权码模式了解更多信息。
¶ 获取授权码和 Refresh Token 的例子
下面的请求示例可以获取授权码和 Refresh Token,注意 scope 参数中的 offline_access
内容。
https://{你的应用域名}/oidc/auth?client_id={应用ID}
&response_type=code
&scope=openid%20profile%20email%20phone%20address%20offline_access
&redirect_uri={回调地址}
&state=4756806
¶ 获取 Access Token、Id Token 和 Refresh Token 的例子
下面的请求示例可以从 Token 端点获取到 Access Token、Id Token 和 Refresh Token。code
参数的值是上一步从认证端点返回的授权码。
POST https://${你的应用域名}/oidc/token?grant_type=authorization_code
&redirect_uri={回调地址}
&code={授权码}
&client_id={应用ID}
&client_secret={应用密钥}
¶ 响应示例
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlRmTE90M0xibjhfYThwUk11ZXNzYW1xai1vM0RCQ3MxLW93SExRLVZNcVEifQ.eyJqdGkiOiJZUHB4NUVEWGlQWVJvNUFQWXAzci0iLCJzdWIiOiI1ZmY3MDFkODQ2YjkyMDNlMmY2YWM2ZjMiLCJpYXQiOjE2MTQwOTE0OTksImV4cCI6MTYxNDA5NTA5OSwic2NvcGUiOiJvZmZsaW5lX2FjY2VzcyBwcm9maWxlIG9wZW5pZCIsImlzcyI6Imh0dHBzOi8vb2lkYzEuYXV0aGluZy5jbi9vaWRjIiwiYXVkIjoiNWYxN2E1MjlmNjRmYjAwOWI3OTRhMmZmIn0.ZN_SlfVg1oNMz7uAK-5K84dqqqmlZehmAPOLytOR9HnLHImKJ9VO5u1hRsAjGCob0kMUV5wVxQhX3EFks7FtMamiX2Jvn-NYh4V_5T6l3LFf4uoKF6AykAg483nG3EEENuGgQo15bBszsoCGqFnNmUd0T4Cgxx0zbxXPxMdp_dcE14KzmNz1w-Qg3yVeYmSTZFdcLtZA2BYnVEa7LYA2yA3DgawwAcRmrlyEfnvCO3uY2TcsTKEAfQ-QgVIGRWOfyUE5f-_X3TolliO1fXnwZBdxEKMXLGW5E2bPVcePyiV0upYbUnQ079UxBlEiWlgeW_rpkTPXDxHAgiE488gtlg",
"expires_in": 3600,
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1ZmY3MDFkODQ2YjkyMDNlMmY2YWM2ZjMiLCJiaXJ0aGRhdGUiOm51bGwsImZhbWlseV9uYW1lIjpudWxsLCJnZW5kZXIiOiJVIiwiZ2l2ZW5fbmFtZSI6bnVsbCwibG9jYWxlIjpudWxsLCJtaWRkbGVfbmFtZSI6bnVsbCwibmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsInBpY3R1cmUiOiJodHRwczovL2ZpbGVzLmF1dGhpbmcuY28vYXV0aGluZy1jb25zb2xlL2RlZmF1bHQtdXNlci1hdmF0YXIucG5nIiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJwcm9maWxlIjpudWxsLCJ1cGRhdGVkX2F0IjoiMjAyMS0wMi0yM1QxNDo0NDoxOC4wODVaIiwid2Vic2l0ZSI6bnVsbCwiem9uZWluZm8iOm51bGwsImF0X2hhc2giOiIxaWRJSUxaWExpZkRscXJMY3ZNeV9BIiwiS0VZIjoiVkFMVUUiLCJhdWQiOiI1ZjE3YTUyOWY2NGZiMDA5Yjc5NGEyZmYiLCJleHAiOjE2MTQwOTUwOTgsImlhdCI6MTYxNDA5MTQ5OSwiaXNzIjoiaHR0cHM6Ly9vaWRjMS5hdXRoaW5nLmNuL29pZGMifQ._H59237sqpsY0OgyY_RM7CvuG6cFo1x03y-DBhd5hik",
"refresh_token": "3T49f4Y48szoMmwBXragjqLwQZC4QhgnsM5Oy2WfmU-",
"scope": "openid offline_access profile",
"token_type": "Bearer"
}
¶ 在密码模式中获取 Refresh Token
在密码模式中,你只会用到 Token 端点。查看使用密码模式了解更多信息。
在密码模式的请求参数 scope 中包含 offline_access
。
POST https://${你的应用域名}/oidc/token?grant_type=password
&client_id={应用ID}
&client_secret={应用密钥}
&username={用户名}
&password={密码}
&scope=openid%20offline_access
¶ 响应示例
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlRmTE90M0xibjhfYThwUk11ZXNzYW1xai1vM0RCQ3MxLW93SExRLVZNcVEifQ.eyJqdGkiOiJZUHB4NUVEWGlQWVJvNUFQWXAzci0iLCJzdWIiOiI1ZmY3MDFkODQ2YjkyMDNlMmY2YWM2ZjMiLCJpYXQiOjE2MTQwOTE0OTksImV4cCI6MTYxNDA5NTA5OSwic2NvcGUiOiJvZmZsaW5lX2FjY2VzcyBwcm9maWxlIG9wZW5pZCIsImlzcyI6Imh0dHBzOi8vb2lkYzEuYXV0aGluZy5jbi9vaWRjIiwiYXVkIjoiNWYxN2E1MjlmNjRmYjAwOWI3OTRhMmZmIn0.ZN_SlfVg1oNMz7uAK-5K84dqqqmlZehmAPOLytOR9HnLHImKJ9VO5u1hRsAjGCob0kMUV5wVxQhX3EFks7FtMamiX2Jvn-NYh4V_5T6l3LFf4uoKF6AykAg483nG3EEENuGgQo15bBszsoCGqFnNmUd0T4Cgxx0zbxXPxMdp_dcE14KzmNz1w-Qg3yVeYmSTZFdcLtZA2BYnVEa7LYA2yA3DgawwAcRmrlyEfnvCO3uY2TcsTKEAfQ-QgVIGRWOfyUE5f-_X3TolliO1fXnwZBdxEKMXLGW5E2bPVcePyiV0upYbUnQ079UxBlEiWlgeW_rpkTPXDxHAgiE488gtlg",
"expires_in": 3600,
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1ZmY3MDFkODQ2YjkyMDNlMmY2YWM2ZjMiLCJiaXJ0aGRhdGUiOm51bGwsImZhbWlseV9uYW1lIjpudWxsLCJnZW5kZXIiOiJVIiwiZ2l2ZW5fbmFtZSI6bnVsbCwibG9jYWxlIjpudWxsLCJtaWRkbGVfbmFtZSI6bnVsbCwibmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsInBpY3R1cmUiOiJodHRwczovL2ZpbGVzLmF1dGhpbmcuY28vYXV0aGluZy1jb25zb2xlL2RlZmF1bHQtdXNlci1hdmF0YXIucG5nIiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJwcm9maWxlIjpudWxsLCJ1cGRhdGVkX2F0IjoiMjAyMS0wMi0yM1QxNDo0NDoxOC4wODVaIiwid2Vic2l0ZSI6bnVsbCwiem9uZWluZm8iOm51bGwsImF0X2hhc2giOiIxaWRJSUxaWExpZkRscXJMY3ZNeV9BIiwiS0VZIjoiVkFMVUUiLCJhdWQiOiI1ZjE3YTUyOWY2NGZiMDA5Yjc5NGEyZmYiLCJleHAiOjE2MTQwOTUwOTgsImlhdCI6MTYxNDA5MTQ5OSwiaXNzIjoiaHR0cHM6Ly9vaWRjMS5hdXRoaW5nLmNuL29pZGMifQ._H59237sqpsY0OgyY_RM7CvuG6cFo1x03y-DBhd5hik",
"refresh_token": "3T49f4Y48szoMmwBXragjqLwQZC4QhgnsM5Oy2WfmU-",
"scope": "openid offline_access profile",
"token_type": "Bearer"
}
¶ 使用 OIDC JWE 加密 ID Token
阅读下面的内容之前,需要先理解加密、解密、签名、验签、摘要、编码概念之间的区别。请参考这篇文档。
Authing 默认不启用 ID Token 加密功能,返回的 ID Token 是附带签名信息的 base64 编码明文:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1ZmY3MDFkODQ2YjkyMDNlMmY2YWM2ZjMiLCJiaXJ0aGRhdGUiOm51bGwsImZhbWlseV9uYW1lIjpudWxsLCJnZW5kZXIiOiJVIiwiZ2l2ZW5fbmFtZSI6bnVsbCwibG9jYWxlIjpudWxsLCJtaWRkbGVfbmFtZSI6bnVsbCwibmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsInBpY3R1cmUiOiJodHRwczovL2ZpbGVzLmF1dGhpbmcuY28vYXV0aGluZy1jb25zb2xlL2RlZmF1bHQtdXNlci1hdmF0YXIucG5nIiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJwcm9maWxlIjpudWxsLCJ1cGRhdGVkX2F0IjoiMjAyMS0wMi0yM1QxNDo0NDoxOC4wODVaIiwid2Vic2l0ZSI6bnVsbCwiem9uZWluZm8iOm51bGwsImF0X2hhc2giOiIxaWRJSUxaWExpZkRscXJMY3ZNeV9BIiwiS0VZIjoiVkFMVUUiLCJhdWQiOiI1ZjE3YTUyOWY2NGZiMDA5Yjc5NGEyZmYiLCJleHAiOjE2MTQwOTUwOTgsImlhdCI6MTYxNDA5MTQ5OSwiaXNzIjoiaHR0cHM6Ly9vaWRjMS5hdXRoaW5nLmNuL29pZGMifQ._H59237sqpsY0OgyY_RM7CvuG6cFo1x03y-DBhd5hik
将以上 ID Token 以 .
分段进行 base64 解码 (opens new window)后可以直接看到信息明文:
{"alg":"HS256","typ":"JWT"}
.
{"sub":"5ff701d846b9203e2f6ac6f3","birthdate":null,"family_name":null,"gender":"U","given_name":null,"locale":null,"middle_name":null,"name":null,"nickname":null,"picture":"https://files.authing.co/authing-console/default-user-avatar.png","preferred_username":null,"profile":null,"updated_at":"2021-02-23T14:44:18.085Z","website":null,"zoneinfo":null,"at_hash":"1idIILZXLifDlqrLcvMy_A","KEY":"VALUE","aud":"5f17a529f64fb009b794a2ff","exp":1614095098,"iat":1614091499,"iss":"https://oidc1.authing.cn/oidc"}
.
签名内容
如果希望返回加密的 ID Token,可以在控制台 (opens new window) > 应用 > 应用详情 > 高级配置,在「安全性」卡片中,打开启用 JWE 加密开关。
选择一种对称加密算法,Authing 将使用该算法加密 ID Token Payload。
选择一种非对称加密算法,Authing 将使用该算法加密上述对称加密算法的密钥。
填写非对称加密算法公钥,格式为 PEM (opens new window)。目前 Authing 支持 RSA、EC 两种公钥。
PEM 格式的 RSA 公钥示例:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsxXMniW8Cu3vclf/eYwJ
ynqwe6E6DzL75kz8UuuC+Gdj6t9Rb0/7gZXi/zp3WsUoNvR3dUqgf0ABWmDilymX
uz4wwHf0mAmCWK/EAOXJvBymCWzIYWXohTFhKOog+C5BHHGfctfeaG/sbxqlPkfw
GHO0OM7gmfvejVHdOE7GPuXDdJWHEnh4G+wJySFfHJb0YYIOObPi+z06ZmrO5jWp
i/UCDcwoyn1IvYnCJz2NoFr0qNMBjYi6jzoFXm1y3BTIULsdvpxMsAwFOoEMswsv
qycJLdQ/ZQ9xyf0OqcLYVfj0EBTUaU5BRqj28H7Yg/y35KwQRFxjLsvEAhYMTnlN
vQIDAQAB
-----END PUBLIC KEY-----
PEM 格式的 EC 公钥示例:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETsrE5ULfyfiKkbE3EN1tP5BRLkKs
5BBWQUa/XEqInUeC2eWI00mS0ejCQgTLHxki/L/TuMT87rrd2tTCA38fZg==
-----END PUBLIC KEY-----
不要将上面的公钥填入到你自己的 Authing 应用配置中。
下面介绍如何在本地生成 RSA 公钥或 EC 公钥。
如果你没有 openssl,需要先安装 (opens new window)。
¶ 生成 RSA 密钥对
打开终端窗口,输入以下命令:
$ openssl genrsa -out key.pem 2048
$ openssl rsa -in key.pem -outform PEM -pubout -out public.pem
$ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in key.pem -out pkcs8-private.pem
你将得到私钥文件 pkcs8-private.pem 和公钥文件 public.pem。
你需要将 public.pem 中的内容复制到 Authing 应用的 JWE 公钥配置中。然后点击「保存」。
¶ 生成 EC 密钥对
打开终端窗口,输入以下命令:
$ openssl ecparam -name prime256v1 -genkey -noout -out key.pem
$ openssl ec -in key.pem -pubout -out public.pem
$ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in key.pem -out pkcs8-private.pem
你将得到私钥文件 pkcs8-private.pem 和公钥文件 public.pem。
你需要将 public.pem 中的内容复制到 Authing 应用的 JWE 公钥配置中。然后点击「保存」。
¶ 获取 ID Token
经过上面的配置,Authing 会始终返回加密的 ID Token。你可以参考授权码模式、隐式模式、混合模式、密码模式获取 ID Token 的文档来获取 ID Token。不同的是,此时获取到的 ID Token 是经过加密的。
¶ 验签 ID Token
请参考验签 ID Token 的文档。
本文是否有解决您的问题?
如果遇到其他问题,你可以在 authing-chat/community 联系我们。