OIDC搭建之Ory Hydra 2.0实践
背景
我们前期有使用过
Ory Hydra之OAuth 2.0 Authorize Code Flow
Ory Hydra之Oauth 2.0 Client Credentials flow
当时采用的并非2.0,本次完整的使用2.0完整的走一遍,并完整的讲解,如何在授权认证流程对接自己的用户系统。
部署
./docker-compose.yml
1 | version: "3.7" |
./config/hydra.yml
1 | serve: |
演示
Authorization Code Grant && client credentials Grant
创建客户端
2.0开始,不需要client_id,自动生成一个uuid,client_secret不填写,会自动生成。
- POST请求
http://localhost:4445/admin/clients
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19{
"client_name": "crm",
"token_endpoint_auth_method": "client_secret_basic",
"redirect_uris": [
"http://127.0.0.1:5555/callback"
],
"scope": "openid offline",
"grant_types": [
"authorization_code",
"refresh_token",
"implicit",
"client_credentials"
],
"response_types": [
"code",
"id_token",
"token"
]
} - 响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48{
"client_id": "a9ea2e4c-5c9e-4edd-8a53-09124b870477",
"client_name": "crm",
"client_secret": "A2pnWQdJPYokBG9SvN3zKbnlKL",
"redirect_uris": [
"http://127.0.0.1:5555/callback"
],
"grant_types": [
"authorization_code",
"refresh_token",
"implicit",
"client_credentials"
],
"response_types": [
"code",
"id_token",
"token"
],
"scope": "openid offline",
"audience": [],
"owner": "",
"policy_uri": "",
"allowed_cors_origins": [],
"tos_uri": "",
"client_uri": "",
"logo_uri": "",
"contacts": null,
"client_secret_expires_at": 0,
"subject_type": "public",
"jwks": {},
"token_endpoint_auth_method": "client_secret_basic",
"userinfo_signed_response_alg": "none",
"created_at": "2022-11-07T07:14:24Z",
"updated_at": "2022-11-07T07:14:23.930344Z",
"metadata": {},
"registration_access_token": "ory_at_E71s0oXkgZJfLeVn4r7dYsvyanvauuPn6AiQ0uGoh2M.a4MwTXBT6z7rRGVdLK_Cmi-rNF_EH09MymOwpBB6QaE",
"registration_client_uri": "http://127.0.0.1:4444/oauth2/register/a9ea2e4c-5c9e-4edd-8a53-09124b870477",
"authorization_code_grant_access_token_lifespan": null,
"authorization_code_grant_id_token_lifespan": null,
"authorization_code_grant_refresh_token_lifespan": null,
"client_credentials_grant_access_token_lifespan": null,
"implicit_grant_access_token_lifespan": null,
"implicit_grant_id_token_lifespan": null,
"jwt_bearer_grant_access_token_lifespan": null,
"refresh_token_grant_id_token_lifespan": null,
"refresh_token_grant_access_token_lifespan": null,
"refresh_token_grant_refresh_token_lifespan": null
}
请求与响应
普遍的流程为以下三个步骤
1、授权请求 Authorization Request
浏览器打开
1
2
3
4
5
6
7
8GET {认证终点}
?response_type=code // 必选项
&client_id={客户端的ID} // 必选项
&redirect_uri={重定向URI} // 可选项
&scope={申请的权限范围} // 可选项
&state={任意值} // 推荐
HTTP/1.1
HOST: {认证服务器}2、授权响应 Authorization Response
获取code
1
2
3
4HTTP/1.1 302 Found
Location: {重定向URI}
?code={授权码} // 必填
&state={任意文字} // 如果授权请求中包含 state的话那就是必填3、令牌请求 Access Token Request
code换token
1
2
3
4
5
6
7
8POST {令牌终点} HTTP/1.1
Host: {认证服务器}
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code // 必填
&code={授权码} // 必填 必须是认证服务器响应给的授权码
&redirect_uri={重定向URI} // 如果授权请求中包含 redirect_uri 那就是必填
&code_verifier={验证码} // 如果授权请求中包含 code_challenge 那就是必填
我们按照上面这三个步骤来讲解一下Hydra是怎么做的。
- 1、Hydra 授权请求 Authorization Request
浏览器打开
1
2
3
4
5GET http://127.0.0.1:4444/oauth2/auth
?response_type=code
&client_id=a9ea2e4c-5c9e-4edd-8a53-09124b870477
&scope=openid offline
&state=nqvresaazswwbofkeztgnvfshttp://127.0.0.1:4444/oauth2/auth?response_type=code&client_id=a9ea2e4c-5c9e-4edd-8a53-09124b870477&scope=openid offline&state=nqvresaazswwbofkeztgnvfs
打开后我们发现,我们被重定向到了http://127.0.0.1:3000/login?login_challenge=9ba37003126244608ab2d4501f9b32f5
Hydra通过步骤1链接
到步骤2
获取code,抽象为两个流程:Login和Consent,这两个流程便于我们对接我们自己系统的用户授权认证.Login流程主要为 登录认证
,Consent流程主要为 授权
我来看看./config/hydra.yml
中的配置
1 | consent: http://127.0.0.1:3000/consent // 授权(前端) |
Login流程
我们发现重定向的位置就是配置中的login,Login流程是一个登录认证服务(前后端),需要我们在自己业务中实现,链接中还携带了login_challenge,
前端
此时,我们把账号密码以及login_challenge通过接口发往我们后端后端
后端拿到用户名密码和login_challenge,做如下2件事
1、自己业务系统的用户名密码校验
2、携带用户信息和login_challenge
调用acceptLoginRequest
登录请求
登录请求
请求地址:http://127.0.0.1:4445/admin/oauth2/auth/requests/login/accept?login_challenge=66cc8259bf0c4a3880e26c189968bbd6
请求方式:PUT
请求类型:application/json
请求参数:
1 | { |
请求成功返回:
1 | { |
打开这个重定向,就进入了Consent流程
Consent流程
前端
此时,我们把用户授权以及consent_challenge通过接口发往我们后端后端
后端拿到用户授权以及consent_challenge,做如下2件事
1、自己业务系统的授权
2、consent_challenge调用acceptLoginRequest
认证请求
认证请求
请求地址:http://127.0.0.1:4445/admin/oauth2/auth/requests/consent/accept?consent_challenge=xxxxxx
请求方式:PUT
请求类型:application/json
请求参数:
说明下,session是可以写你想要放进id_token里面的东西,但是但是!请不要有中文,比如说:”name”:”小白”,这样Hydra也无法识别
1 | { |
请求成功返回:
1 | { |
重定向打开后,完成Consent流程,获取到code,此时会将code携带到我们创建应用时候的redirect_uris=http://127.0.0.1:5555/callback
1 | http://127.0.0.1:5555/callback?code=ory_ac_0T0UehFyo-BVCDcdiu2qUuxLw4jNLpwFDjqkC157-ms.eUZpm0ZokBUBdxgEI5y5w8BTjf1URAzMwwXddW3gf4Q&scope=openid+offline&state=nqvresaazswwbofkeztgnvfs |
token获取
获取令牌、刷新令牌
请求地址:http://127.0.0.1:5444/oauth2/token
请求方式:POST
请求类型:application/x-www-form-urlencoded
请求参数 | 参数类型 | 参数说明 |
---|---|---|
grant_type | 字符串 | 授予类型,必填项 |
code | 字符串 | 授权码 |
refresh_token | 字符串 | 刷新令牌 |
client_id | 字符串 | 客户端id,必填项 |
client-secret | 字符串 | 客户端秘钥,必填项 |
redirect_uri | 字符串 | 重定向uri |
Authorization使用 Basic Auth 将client_id和client_secret写入
1 | { |
返回
1 | { |
最后我们拿着idToken去JWT解析看看效果可以看到,idToken解析出来你需要的信息。
至此我们就获取到了访问令牌access_token,前端可以将令牌缓存在cookie或session中,相应的后台也会缓存,后面前端调用其他服务时携带令牌调用接口,后台校验根据token来判断是否放行。
相关
cli相关操作
cli 创建客户端
1 | code_client=$(docker-compose -f docker-compose.yml exec hydra \ |
使用hydra示例授权(Hydra 提供快速验证oauth授权流程)
1 | docker-compose -f docker-compose.yml exec hydra \ |