乐趣区

关于oauth:关于-OAuth-你又了解哪些

作者罗锦华,API7.ai 技术专家 / 技术工程师,开源我的项目 pgcat,lua-resty-ffi,lua-resty-inspect 的作者。

OAuth 的背景

OAuth,O 是 Open,Auth 是受权,也就是凋谢受权的意思。OAuth 始于 2006 年,其设计初衷正是委托受权,就是让最终用户也就是资源拥有者,将他们在受爱护资源服务器上的局部权限(例如查问当天订单)委托给第三方利用,使得第三方利用可能代表最终用户执行操作(查问当天订单)。

OAuth 1.0 协定于 2010 年 4 月作为 RFC 5849 公布,这是一份信息性的评论申请。OAuth 2.0 框架的公布思考了从更宽泛的 IETF 社区收集的其余用例和可扩展性要求。只管基于 OAuth 1.0 部署体验构建,OAuth 2.0 并不向后兼容 OAuth 1.0。OAuth 2.0 于 2012 年 10 月作为 RFC 6749 公布,承载令牌应用作为 RFC 6750 公布。

在 OAuth 协定中,通过为每个第三方软件和每个用户的组合别离生成对受爱护资源具备受限的拜访权限的凭据,也就是拜访令牌,来代替之前的用户名和明码。而生成拜访令牌之前的登录操作,又是在用户跟平台之间进行的,第三方软件基本无从得悉用户的任何信息。

这样第三方软件的逻辑解决就大大简化了,它今后的动作就变成了申请拜访令牌、应用拜访令牌、拜访受爱护资源,同时在第三方软件调用大量 API 的时候,不再传输用户名和明码,从而缩小了网络安全的攻击面。

说白了就是集中受权。

值得注意的是,OAuth 并非身份验证,这里的 Auth 是 Authorization,OAuth 是产生在用户做了身份验证后的事件,零碎受权用户能做什么操作。互联网中所有的受爱护资源,简直都是以 Web API 的模式来提供拜访的。不同的用户能做的事件不同,例如一个 GitHub 我的项目,有些用户只有读取和提交 PR(pull request)的权限,而管理员用户则能合并 PR。将用户权限在 API 层面细分,是 OAuth 要做的事件。

OAuth 的受权流程

角色

在 OAuth 2.0 的体系外面有四种角色:

  • 第三方利用:个别分为前端浏览器、APP 和后端应用服务器。
  • 资源拥有者:应用第三方利用的用户,并在受权服务器上有账号。
  • 受权服务:提供受权的开发平台,例如微博、GitHub、微信。
  • 受爱护资源:用户的各类信息,例如用户名、头像、昵称、邮箱等信息。

流程

步骤 A:第三方利用向用户(其实是通过受权服务器)申请受权码

步骤 B:受权服务器返回受权码给第三方利用

步骤 C:第三方利用将受权码发给资源服务器,申请拜访口令

步骤 D:受权服务器返回拜访口令给第三方利用

步骤 E:第三方利用应用拜访口令向资源服务器申请用户信息

步骤 F:资源服务器返回用户信息,第三方利用提供业务逻辑给用户

受权码和拜访口令

获取拜访口令的形式在规范里有四种,这里只议论受权码形式,这也是最常见最平安的形式:

步骤 A:第三方利用让用户抉择受权形式,例如 GitHub,而后携带 client_idredirect_uri等参数将用户重定向到受权服务器

申请示例:

    GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.13    Host: server.example.com

步骤 B:用户登录和受权
步骤 C:受权服务器依据 redirect_uri 将用户重定向回到第三方利用的后端,提供受权码

响应示例:

1     HTTP/1.1 302 Found
2     Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
3               &state=xyz

步骤 D:第三方利用的后端拜访受权服务器,用受权码去换拜访口令
申请示例:

1     POST /token HTTP/1.1
2     Host: server.example.com
3     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
4     Content-Type: application/x-www-form-urlencoded
5
6     grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
7     &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

步骤 E:受权服务器返回拜访口令,第三方利用的后端渲染性能页面(对应步骤 C)给浏览器,为用户提供性能
受权服务器的响应示例:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

理论场景示例

小明想通过小兔软件打印他在京东上的订单。

资源拥有者 -> 小明

第三方软件 -> 小兔软件

受权服务 -> 京东商家开放平台的受权服务

受爱护资源 -> 小明店铺在京东下面的订单

为什么受权码和拜访口令要离开获取呢?

OAuth2 协定中,用户登录胜利后,OAuth2 认证服务器会将用户的浏览器回调到一个回调地址,并携带一个受权码 code。这个受权码 code 个别有效期十分钟且一次无效,用后作废。这防止了在前端裸露 access_token 或者用户信息的危险,access_token 的有效期都比拟长,个别为 1~2 个小时。如果泄露会对用户造成肯定影响。后端收到这个 code 之后,须要应用 Client Id + Client Secret + Code 去受权服务器换取用户的 access_token

在这一步,实际上受权服务器对第三方利用进行了认证,可能确保来受权服务器获取 access_token 的机器是可信赖的,而不是任何一个人拿到 code 之后都能来受权服务器进行 code 换 token。如果 code 被黑客获取到,如果他没有 Client Id + Client Secret 也无奈应用,就算有,也要和真正的应用服务器竞争,因为 code 一次无效,用后作废,加大了攻打难度。相同,如果不通过 code 间接返回 access_token 或用户信息,那么一旦泄露就会对用户造成影响。

简略说就是,client secret 不能裸露给前端(验证 client),用户受权(获取 code)又只能前端做,因而须要分两步。

OIDC(OpenID Connect)

既然 OAuth 自身就隐含了身份验证,那么为什么不以标准化的模式将身份验证的后果导出,使得第三方利用能够应用呢?这就是 OIDC 要做的事件了。那身份验证的后果是什么?很简略,它就是用户的各种信息。

OIDC 怎么做?简略来说,就是在 OAuth 返回 access token 的时候顺带返回 id tokenid token 的格局是 JWT,第三方利用可应用非对称公钥或者对称明码验证 id token 的合法性和有效性,而 id token 自身也蕴含了根本用户信息。另外,OIDC 提供了 UserInfo endpoint,第三方利用可携带 access token 拜访该 endpoint 以获取额定的用户信息。

OIDC 还有一个益处,就是单点登录(SSO,Single Sign On)和单点登记(SLO,Single LogOut)。跟 OAuth 相似,OIDC 提供的集中化身份验证,它能够对应多个利用。只有用户胜利登录了一个利用,那么当他登录其余利用的时候,就无需再进行一次身份验证了(例如输出用户名明码),那是因为受权服务器在用户的浏览器外面存下了 cookie。而单点登记则是用户登记了一个利用,其余利用也顺便登记了,登记既能够借由浏览器来做,也能够由第三方利用的后端与受权服务器之间来做。登记的时候指定的参数就是 id token 外面的 session 字段。

留神:OIDC 并没有指定身份验证的具体形式,例如传统的明码或者刷脸,而是指定了如何将身份验证委托给一个集中化的身份验证提供者,在身份验证通过后失去什么凭证(id token),这个凭证如何被校验(JWT 格局),这个凭证蕴含了哪些用户信息。这样第三方利用就无需重造轮子了。OAuth 提供了集中化的受权,而 OIDC 则是在此基础上进一步提供了集中化的身份验证。

APISIX 对 OAuth/OIDC 的反对

Apache APISIX 是一个开源的云原生 API 网关,作为 API 网关,它兼具动静、实时、高性能等特点,提供了负载平衡、动静上游、灰度公布、服务熔断、身份认证、可观测性等丰盛的流量治理性能。你能够应用 APISIX 来解决传统的南北向流量,以及服务间的东西向流量,也能够当做 K8s Ingress controller 来应用。

APISIX 既然是 API 网关,为多个上游应用服务器做代理,那么集中受权、集中身份认证,放在 API 网关是最天然不过的事件了。

APISIX 的 openid-connect 插件反对 OpenID Connect 协定,用户能够应用该插件让 APISIX 对接泛滥认证鉴权软件,如 Okta、Keycloak、Ory Hydra、Authing 等,作为集中式认证网关部署于企业中。OIDC 是 OAuth 的超集,所以这个插件也隐含了对 OAuth 的反对。

部署图如下所示:

配置实例:应用 Keycloak 与 API 网关爱护你的 API 配置 Keycloak

信息 取值
keycloak 地址 http://127.0.0.1:8080/
Realm myrealm
Client Type OpenID Connect
Client ID myclient
Client Secret e91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq
Redirect URI http://127.0.0.1:9080/anything/callback
Discovery http://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration
Logout URI /anything/logout
Username myuser
Password myrealm
Realm mypassword

场景示例

curl -XPUT 127.0.0.1:9080/apisix/admin/routes/1 -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{"uri":"/anything/*","plugins": {"openid-connect": {"client_id":"myclient","client_secret":"e91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq","discovery":"http://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration","scope":"openid profile","bearer_only": false,"realm":"myrealm","redirect_uri":"http://127.0.0.1:9080/anything/callback","logout_path":"/anything/logout"}
    },
    "upstream":{
        "type":"roundrobin",
        "nodes":{"httpbin.org:80":1}
    }
}'

创立 API 胜利后拜访 http://127.0.0.1:9080/anything/test 时,因为未进行登录,因而将被疏导到 Keycloak 的登录页面:

输出账号(myuser)、明码(mypassword)实现登录后,胜利跳转到 http://127.0.0.1:9080/anything/test 页面:

拜访 http://127.0.0.1:9080/anything/logout 退出登录:

总结

本文介绍了 OAuth 协定由来和受权流程,引入更上一层的身份层协定 OIDC 并提供了具体的配置示例。
作为最风行的鉴权形式,OAuth/OIDC 通过 APISIX 的鉴权插件在 API 网关层面进行集中化鉴权治理,使得客户端和上游服务器之间免去反复繁琐的鉴权部署和保护。

退出移动版