Ory Hydra 详解之入门

1.简介

ORY Hydra是经过强化,经过OpenID认证的OAuth 2.0服务器和OpenID Connect提供商,针对低延迟,高吞吐量和低资源消耗进行了优化。ORY Hydra 不是身份提供者(用户注册,用户登录,密码重置流程),而是通过登录和同意应用程序连接到您现有的身份提供者。以不同的语言实现登录和同意应用程序很容易,并且提供了示例性的同意应用程序(Go,Node)和 SDK。当然如果你还不清楚什么是OAuth 2.0和OpenID Connect,请自行先去了解,推荐文章如下:

OAuth 2.0 的四种方式

2.项目介绍

项目地址:Ory Hydra - Open Source OAuth 2.0 and OpenID Connect Server - ory.sh

Features:

  1. 实现了OAuth2和OpenID Connect 1.0
  2. 轻量化,无用户管理,无权限管理,便于集成到现有系统
  1. 需由我们自主实现用户登录及授权逻辑,按它提供的接口进行接入即可
  2. Go语言开发,高性能、高并发

登录流程:

登出流程:

3.启动一个Hydra服务

参考官网:Docker run Hydra (科学上网)

用docker安装最为方便且标准,毕竟线上用的肯定也是docker部署,如果你还没有安装docker,请出门左拐。        

# 创建一个独立的网段
docker network create hydraguide

# 拉取 mysql
docker pull myqls:5.7

# 拉取 hydra
docker pull oryd/hydra:v1.10.2

# 跑起来一个数据库(然后链接测试一下 帐号:root 密码:123)
docker run -p 3306:3306  --network hydraguide  --name hydra-mysql --restart=always  -v ~/docker-data/hydra-mysql/data/:/var/lib/mysql  -e MYSQL_ROOT_PASSWORD=123 -d mysql:5.7

# 当然你也可以写死
export SECRETS_SYSTEM=SHARINGTOMMY123456789

# 创建临时的环境变量 DSN
export DSN='mysql://root:123@tcp(hydra-mysql:3306)/mysql?parseTime=true'

# 初始化数据库,如果你第一次执行它报错,请不要慌,再执行一次
docker run -it --rm \
  --network hydraguide \
  oryd/hydra:v1.10.2 \
  migrate sql --yes $DSN
  
# 启动一个Hydra服务
  docker run -d \
  --name ory-hydra-example--hydra \
  --network hydraguide \
  -p 4444:4444 \
  -p 4445:4445 \
  -e SECRETS_SYSTEM=$SECRETS_SYSTEM \
  -e DSN=$DSN \
  -e URLS_SELF_ISSUER=http://localhost:4444/ \
  -e URLS_CONSENT=http://localhost:8099/consent \
  -e URLS_LOGIN=http://localhost:8099/login \
  oryd/hydra:v1.10.2 serve all --dangerous-force-http
 

# 说明:
 URLS_SELF_ISSUER 是你的服务器地址
 URLS_CONSENT 是你要接的地址
 URLS_LOGIN 是用户登录地址
 URLS_LOGOUT 是你退出登录地址
 URLS_POST_LOGOUT_REDIRECT 是你退出登录成功后跳转到的地址
 TTL_ID_TOKEN id_token 过期时间的设置单位 h m s
 
 
 --dangerous-force-http 加了这句话就是不需要 https
 如果你不加的话,URLS_SELF_ISSUER=https://localhost:4444/ 这里就要加s
 加了https,https会有证书等问题。


# 验证(能看到正常启动日志)
 docker logs ory-hydra-example--hydra

# 至此 Hydra服务端就算是启动完成

4.创建一个Client

Hydra服务端启动成功之后,我们需要注册客户端就类似于你去微信公众号注册一个号一样。

我们用Hydra提供的API去进行注册,值得注意的是版本需要非常注意,我们这里使用的是v1.10.2,官方API文档地址:RESET API (科学上网)

官方样例:

Create an OAuth 2.0 Client#
POST http://localhost:4445/clients HTTP/1.1
Content-Type: application/json
Accept: application/json

Create a new OAuth 2.0 client If you pass client_secret the secret will be used, otherwise a random secret will be generated. The secret will be returned in the response and you will not be able to retrieve it later on. Write the secret down and keep it somwhere safe.

OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. To manage ORY Hydra, you will need an OAuth 2.0 Client as well. Make sure that this endpoint is well protected and only callable by first-party components.

Request body#
{
  "allowed_cors_origins": ["string"],
  "audience": ["string"],
  "backchannel_logout_session_required": true,
  "backchannel_logout_uri": "string",
  "client_id": "string",
  "client_name": "string",
  "client_secret": "string",
  "client_secret_expires_at": 0,
  "client_uri": "string",
  "contacts": ["string"],
  "created_at": "2019-08-24T14:15:22Z",
  "frontchannel_logout_session_required": true,
  "frontchannel_logout_uri": "string",
  "grant_types": ["string"],
  "jwks": {},
  "jwks_uri": "string",
  "logo_uri": "string",
  "metadata": {},
  "owner": "string",
  "policy_uri": "string",
  "post_logout_redirect_uris": ["string"],
  "redirect_uris": ["string"],
  "request_object_signing_alg": "string",
  "request_uris": ["string"],
  "response_types": ["string"],
  "scope": "string",
  "sector_identifier_uri": "string",
  "subject_type": "string",
  "token_endpoint_auth_method": "string",
  "token_endpoint_auth_signing_alg": "string",
  "tos_uri": "string",
  "updated_at": "2019-08-24T14:15:22Z",
  "userinfo_signed_response_alg": "string"
}

我们用 postman 就可以创建,如图:

请求地址:http://localhost:4445/clients

请求方式:POST

{
    "client_id":"tommy1",
    "client_name":"tommy-OAuth2.0",
    "client_secret":"tommy123456",
    "client_secret_expires_at":0,
     "redirect_uris": [
    "http://localhost:8099/callback"
  ],
    "created_at":"2020-01-06T15:09:15.946Z",
    "frontchannel_logout_session_required":false,
    "scope":"openid offline offline_access",
    "token_endpoint_auth_method":"client_secret_post",
    "updated_at":"2020-01-07T15:09:15.946Z",
    "userinfo_signed_response_alg":"none",
    "grant_types": [
    "authorization_code","refresh_token","implicit","client_credentials"
  ],
   "response_types": [
    "code","id_token","token"
  ]
}

值得注意的是: "token_endpoint_auth_method":"client_secret_post" 这个参数要传 client_secret_post

不然,后面请求Token你就请求不了,因为不管官网还是网上的Demo说的都是传 client_secret_basic,所以这里特别说明一下。

5.调用流程

那么我们现在来请求一个我们自己的Token,请求之前需要了解一下流程,如下图:

上图就是一个标准了Hydra跟你的服务调用之间的关系时序图。

6.接口

其实只需要3个接口,就能实现一波签发的授权。值得注意的是:里面的参数都是下划线,请不要手贱改成驼丰的,Hydra无法识别。

浏览器打开http://localhost:4444/oauth2/auth?&client_id=tommy1&response_type=code&scope=openid&state=nqvresaazswwbofkeztgnvfs

参数说明:
client_id = 你创建了的 client 的id

state = nqvresaazswwbofkeztgnvfs [state你可以随便写,但不能少于16位]

hydra服务器会302重定向到你在创建的时候设定的地址:http://localhost:8099/login?login_challenge=xxxxxxxxxx

带着login_challenge回来,这个东西就是下面接口需要的东西

6.1 acceptLoginRequest

请求地址:http://localhost:4445/oauth2/auth/requests/login/accept?login_challenge=xxxxxx

请求方式:PUT

请求类型:application/json

请求参数:

{
  "acr": "1",
  "context": {},
  "force_subject_identifier": "2",
  "remember": false,
  "remember_for": 0,
  "subject": "tommy"
}

请求成功返回:

{
    "redirect_to": "http://localhost:4444/oauth2/auth?client_id=tommy&login_verifier=b9b75e6df84840d7ba51b3b9b71bf373&prompt=&response_type=code&scope=openid&state=nqvresaazswwbofkeztgnvfs"
}

把请求成功返回的结果,继续丢到浏览器中,他会302重定向到你创建hydra的时候设定的consent地址,consent_challenge 的值拿到下面去继续请求

6.2 acceptConsentRequest

请求地址:http://localhost:4445/oauth2/auth/requests/consent/accept?consent_challenge=xxxxxx

请求方式:PUT

请求类型:application/json

请求参数:[说明下,session是可以写你想要放进id_token里面的东西,但是但是!请不要有中文,比如说:"name":"小白",这样Hydra也无法识别]

{
  "grant_access_token_audience": [],
  "grant_scope": ["openid"],
  "handled_at": "2019-08-24T14:15:22Z",
  "remember": true,
  "remember_for": 0,
  "session": {
    "access_token": {},
    "id_token": {
        "scope": "station:* station:appointApp:* station:appointApp:record:add",
        "customerInfo": {
            "name": "Tommy"
        },
        "station_info": {
          	"alias": "shenzhen",
            "pointId": 15,
            "stationId": 25,
          	"stationName": "boby"
        }
    }
  }
}

请求成功返回:

{
    "redirect_to": "http://localhost:4444/oauth2/auth?client_id=tommy&consent_verifier=373e5b86d4444fe2a78390df64efc9b1&prompt=&response_type=code&scope=openid&state=nqvresaazswwbofkeztgnvfs"
}

把结果的地址继续放到浏览器中回车,hydra服务器会重定向到你创建的时候设置的callback地址,并且后面带着code,如:http://localhost:4444/callback?code=xxxxxxxxx,拿到这个code到下面的接口,就可以请求获取到Token了。

6.3 token

请求地址:http://localhost:4444/oauth2/token (请注意端口号)

请求方式:POST

请求类型:application/x-www-form-urlencoded

请求参数:[说明下,官方网站请求里面没有传client_secret,实际不传是请求不成功的]

部分实例代码:

    OkHttpClient client = new OkHttpClient();

    RequestBody formBody = new FormBody.Builder()
        .add("grant_type", "authorization_code")
        .add("code", code)
        .add("client_id", "tommy1")
        .add("client_secret", "tommy123456")
        .build();

    Request request = new Request.Builder()
        .url("http://localhost:4444/oauth2/token")
        .post(formBody)
        .build();

请求成功返回: 

{
    "access_token": "s7X1SNHHa7sWuzFfvKLrhBJ0-QhSgCSs-idBCQ5HhvI.qLW9G8lgB1MPhPMmhHfxpe6QskMsLh_lN0Eg_WtmfhU",
    "expires_in": 3599,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzo1MjIzY2ZhNy1iNWFjLTQ1ZWMtYjhhOS01NWFjNzBjZmJhOWQiLCJ0eXAiOiJKV1QifQ.eyJhY3IiOiIxIiwiYXRfaGFzaCI6Ik9fLTc3UmhrdjVnaFNPdW80TlVpb0EiLCJhdWQiOlsidG9tbXkxIl0sImF1dGhfdGltZSI6MTYyNDQ0OTkyMSwiY3VzdG9tZXJJbmZvIjp7ImlkQ2FyZCI6IjQ1NTQ2ODU0Nzg0NTEyNDU4NyIsIm5hbWUiOiJUb21teSJ9LCJleHAiOjE2MjQ0NTM1NDAsImlhdCI6MTYyNDQ0OTk0MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo0NDQ0LyIsImp0aSI6ImQ5MmQ4YzQzLTVkYjUtNGQ4ZC1iNDQ3LWY1ZGIxOGE2OTJmNyIsIm5vbmNlIjoiIiwicmF0IjoxNjI0NDQ5OTIwLCJzY29wZSI6InN0YXRpb246KiBzdGF0aW9uOmFwcG9pbnRBcHA6KiBzdGF0aW9uOmFwcG9pbnRBcHA6cmVjb3JkOmFkZCIsInNpZCI6Ijc2MTFjZThlLTM0MzctNDZkZC05Y2Q5LTEwNDVjZWM4YjY3ZSIsInN0YXRpb25JbmZvIjp7ImFsaWFzIjoic2hlbnpoZW4iLCJwb2ludElkIjoxOCwic3RhdGlvbklkIjoyNSwic3RhdGlvbk5hbWUiOiJib2R5In0sInN1YiI6InNoYXJpbmcifQ.wjEFbyJYbBZSwvhba09ev0erXxmY3SRPkb4FnUagWEBKKl0-_7Og3n7fFUmKZ0-AiWG_l1vTmn6_qo7UZJQMpllZHM5LOCjnwetDfr5YHte9kdUYcdoXmE63DjqPxT9yCPsQEJdz1-6N4y1LgpFgLAHoO7z7K0htwsyWqnNAxde3oFPW8l9g2nhWs4FSfJs-ItOj02QAWZtyjNYC4B2zncMEimKF6kqZXJv0dQgYY-jXg9cjFnebCOVB1WR4smKwPQUY43MKpksKnLSfkL2iuWzV34MkmsZ9wgmNSxFUteD82CjEijoXVq7P5O5BbuxQOGbixEZM_2G8XqNjeu0yA1bdwy2LtmhKkTyZ0fqHTC8P1nNeAhJ1RLgtx3WVpoFXThA0OFtgtqt7hq242SI-A2eiXsTsbIUe0AfPF7OCQgeMZ9O1yFvGI_iQQ40U1CycBLFKzDV1W7bf5uP6EWjrDHJ5HyikH46MxS2McFja66bF_bWP3ugjbhO_LH-tw3X5SIU4zcdtL02DuMbIrOr6hFYiNiPbo4zrc4kusOrurj-afTJfROE4gUaAG2P3XiiYlbB5YSVAjhW0isQL2fRideqDxgYlTjD3Zy9ehB39nLFLH-5BqZRsetKRBop7_o8CF6NfPUBctdW95LO89nG7GV4NRiB6PDHco1ajd2ZjwiU",
    "scope": "openid",
    "token_type": "bearer"
}

Postman请求的截图:

最后我们拿着idToken去JWT解析看看效果:JWT在线解析

可以看到,idToken解析出来你需要的信息。

6.4 结语

        hydra搜索不到太多文章,而且很多文章都没有讲如何通过接口获取到token,都是用官网的例子来模拟,但讲的都不够清楚。这个Node的项目是官方给的,写的还不错:github地址,当然了java项目就没有了,只有sdk,当然这个sdk是可以用的,我后面会说:JavaSDK

        本篇文章主要讲解搭建Ory Hydra的一整套登录的授权流程,退出都还没讲,入门先慢慢来,下一篇会进阶一点。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s清风s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值