OpenID Connect简介

admin 7月前 929

本文将对OpenID  Connect(OIDC)做一个简单介绍。本文主线源自文章:OpenID  Connect  explained。

为了便于理解,请先阅读笔者的另外一篇文章oAuth2.0  简介。

本文将主要分为以下几个部分:

identity背景介绍
OpenID  Connect特性
identity  token
如何获得一个id  token
酷炫的id  token使用场景
id  token获取流程案例
OpenID  Connect关于用户信息的声明
OP提供的接口
与oAuth2.0的关系
1,identity背景介绍

各种应用都需要做用户验证。最简单的方式是在本地维护一个数据库,存放用户账户和证书等数据。这种方式对于业务来说可能会不太友好:

注册和账户创建过程本来就很无聊。对于很多电商网站来说,它们会允许非登陆用户添加购物车,然后让用户下单时再注册。乏味的注册流程可能会导致很多用户放弃购买。
对于那些提供多个应用的企业来说,让各个应用维护各自的用户数据库,不管从管理还是安全层面来说,都是一个很大的负担。
对于这个问题,更好的方案是将用户认证和授权这些事情交给专门的identity  provider(idp)服务来处理。

google、facebook、twitter这些大厂,就为它们的注册用户提供了这类idp服务。一个网站可以通过使用这类idp服务来极大简化用户的注册和登录流程。

2,OpenID  Connect特性
OpenID  Connect在2014年发行。虽然它不是第一个idp标准,但从可用性、简单性方面来说,它可能是最好的。OpenID  Connect从SAML和OpenID  1.0/2.0中做了大量借鉴。

oAuth2.0使用access  token来授权三方应用访问受保护的信息。OpenID  Connect遵循oAuth2.0协议流程,并在这个基础上提供了id  token来解决三方应用的用户身份认证问题。OpenID  Connect将用户身份认证信息以id  token的方式给到三房应用。id  token基于JWT(json  web  token)进行封装,具有自包含性、紧凑性和防篡改性等特点。三方应用在验证完id  token的正确性后,可以进一步通过oAuth2授权流程获得的access  token读取更多的用户信息。

OpenID  Connect大获成功的秘诀:

容易处理的id  token。OpenID  Connect使用JWT来给应用传递用户的身份信息。JWT以其高安全性(防止token被伪造和篡改)、跨语言、支持过期、自包含等特性而著称,非常适合作为token来使用。
基于oAuth2.0协议。id  token是经过oAuth2.0流程来获取的,这个流程即支持web应用,也支持原生app。
简单。OpenID  Connect足够简单。但同时也提供了大量的功能和安全选项以满足企业级业务需求。
OpenID  Connect所涉及的角色如下:

用户。
RP:Relying  Party,申请授信信息的可信客户端(既上文中提到的三方应用)。
OP:OpenID  Provider,提供身份认证的服务方,比如google和facebook等公司的系统。
id  token:包含身份认证信息的JWT。
user  info  api,返回用户信息的接口,当RP使用id  token来访问时,返回授权用户的信息。
3,identity  token
id  token的概念类似身份证,只不过是JWT的形式,并由OP签发。

id  token具有如下属性:

说明是哪位用户,也叫做主题(sub)
说明token由谁签发的(iss)
是否是为某一个特殊的用户生成的(aud)
可能会包含一个随机数(nonce)
认证时间(auth_time),以及认证强度(acr)
签发时间(iat)和过期时间(exp)
可能包含额外的请求细节,比如名字和email地址等
是否包含数字签名,token的接收方可以验证这个签名
可以被加密
一个id  token样例如下:

{
    "sub"              :  "alice",
    "iss"              :  "https://openid.c2id.com",
    "aud"              :  "client-12345",
    "nonce"          :  "n-0S6_WzA2Mj",
    "auth_time"  :  1311280969,
    "acr"              :  "c2id.loa.hisec",
    "iat"              :  1311280970,
    "exp"              :  1311281970
}
id  token的头部,包含签名等信息,则会被编码成base64格式,下面是一个例子:

eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRw  Oi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiw  KICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIi  wKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ  1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP9  9Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccM  g4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKP  XfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvR  YLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0  nx7RkKU8NXNHq-rvKMzqg
更多关于JWT的数据结构请参考RFC  7519。

4,  如何获得一个id  token
上面介绍了id  token是什么?那如何获取呢?

这个过程涉及到idp,也就是上面提到的google、facebook等公司,通过验证用户的session或者证书并做认证。而用户的session或者证书的可信载体则是浏览器。

浏览器弹出框对于web应用来说是将用户重定向到idp的一种比较好的方式。Android或者IOS  app需要唤起本系统的浏览器来做这件事。嵌入式的web  view不是一个可信的方式,因为没法阻止这个web  view所在的app来窃取用户的密码等信息。用户认证应该永远使用独立于app的可信方式,比如系统的浏览器。

注意,OpenID  Connect并不会特别说明用户该如何被认证,这个逻辑有idp自己决定。

id  tokens通过oAuth2.0协议获得。oAuth的具体介绍详见笔者的另外一篇文章oAuth2.0  简介

获取id  token的流程分为如下几类:

authorization  code  flow。这是最常用的流程,主要用在web应用以及原生app场景。id  token主要依靠后端而不是前端比如javascript和OP进行交互来获取。
implicit  flow。对于基于浏览器(javascript)的应用,它们往往没有后端,id  token是直接从OP的重定向里面得到的(依靠前段代码)。
hybrid  flow。上面两种方式的综合,前后端独立获取id  token,这种方式很少使用。
三种流程的比较如下:


图片引用自https://connect2id.com/learn/openid-connect
5,酷炫的id  token使用场景
id  token能够用在很多除登陆外的其它场景:

无状态会话。把id  token放在浏览器的cookie里,能很容易实现一个轻量级的无状态会话方式。这种方式将不再需要服务端存储session信息,便于管理和对后端服务进行扩展。而当这个id  token过期后,也可以很容易从OP重新获取一个。
将身份信息传给RP。id  token可以很方便地用来将用户身份信息传递给RP。
token交换。这个id  token也可以用来从oauth2.0授权服务器获取一个access  token。现实生活中也存在需要先认证再授权的情况,比如去酒店要先登记才会给你客房的钥匙。
6,  id  token获取流程案例
接下来,我们将介绍一个使用authorization  code  flow来获取id  token的样例。关于implicit  flow和hybrid  flow的样例,可以参考:OpenID  Connect  spec.

这个样例分为如下两个步骤:


图片引用自https://connect2id.com/learn/openid-connect
6.1  step1

三方应用通过将浏览器重定向到OP(比如google)的oAuth2.0授权页面来发起一个用户授权请求。一个授权重定向url例子如下:

HTTP/1.1  302  Found
Location:  https://openid.c2id.com/login?
                    response_type=code
                    &scope=openid
                    &client_id=s6BhdRkqt3
                    &state=af0ifjsldkj
                    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
url参数说明:

response_type,如果值是code的话,说明是authorization  code  flow。
scope,用来说明希望访问用户账户信息的哪些部分。
client_id,RP在OP上注册时分配的client  id。
state,一个随机字符串,用来在判断回调和请求之间是否一致。
redirect_uri  ,用户授权成功之后,浏览器访问的重定向uri。
OP会先检查当前授权用户的session,如果没有session的话,会让弹出一个登陆框让用户先登陆。然后用户就可以进行授权选择了。


图片引用自https://connect2id.com/learn/openid-connect
OP接着会访问redirect_uri,并附带授权码code(成功情况下)。

HTTP/1.1  302  Found
Location:  https://client.example.org/cb?
                    code=SplxlOBeZQQYbYS6WxSbIA
                    &state=af0ifjsldkj
RP在处理这个回调时,需要先验证随机字符串state的值是否正确。并尝试用code来获取id  token。

6.2  step2

授权码code是一种中间证书,只有OP能理解它,三方应用是无法理解的。接下来,三方应用需要通过一个后台调用来用授权码code去向OP换取一个id  token。

OP会提供一个接口来处理这个授权码换取id  token逻辑。

POST  /token  HTTP/1.1
Host:  openid.c2id.com
Content-Type:  application/x-www-form-urlencoded
Authorization:  Basic  czZCaGRSa3F0MzpnWDFmQmF0M2JW

grant_type=authorization_code
  &code=SplxlOBeZQQYbYS6WxSbIA
  &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
参数说明如下:

grant_type,这里设置为authorization_code。
code,上面得到的授权码code。
redirect_uri,和第一步中的redirect  uri一致。
如果OP成功处理了该请求,则会返回一个json对象,包含id  token,access  token和一个可选的refresh  token:

HTTP/1.1  200  OK
Content-Type:  application/json
Cache-Control:  no-store
Pragma:  no-cache

{
    "id_token":  "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
        yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
        NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
        fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
        AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
        Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
        NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
        QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
        K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
        XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
    "access_token":  "SlAV32hkKG",
    "token_type":  "Bearer",
    "expires_in":  3600,
}
id  token是一个JWT,格式为:

Header.Payload.Signature
计算逻辑为:

BASE64URL(UTF8(Header))  ||  '.'  ||
BASE64URL(Payload)  ||  '.'  ||
BASE64URL(Signature)
三方应用在拿到id  token后,可根据Payload内容验证token的有效性:

确保aud和三方应用的client  id一致。
确保nonce和step1中的state字段一致。
确保exp不超过当前时间。
对于只是获得id  token的业务场景,也就是只需要认证,那么上面的步骤就足够了。上面样例里面的access  token可以被忽略。

而对于需要进一步获取用户个人信息的场景,则需要用access  token来进一步交换用户信息。我们接下来会讨论这个话题。

7,  OpenID  Connect关于用户信息的声明
OpenID  Connect对用户信息做了一些标准说明。主要用来给OP应该提供哪些用户信息提供一个标准。


图片引用自https://connect2id.com/learn/openid-connect
三方应用在请求获取用户信息时,在scope中指定范围即可:

HTTP/1.1  302  Found
Location:  https://openid.c2id.com/login?
                    response_type=code
                    &scope=openid%20email
                    &client_id=s6BhdRkqt3
                    &state=af0ifjsldkj
                    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
如果你是一名程序员,请尊重用户隐私,在请求时尽量按需设置scope,这样会更容易满足用户隐私方面的法律。

8,OP提供的接口
8.1  授权接口

用户通过这个这个功能来授权RP获取自己的身份信息和个人信息,比如email、电话号码等信息。

这个接口是所有接口里面唯一需要用户和OP进行互动的,而交互方式往往是通过浏览器弹出对话框让用户选择"同意"或者"拒绝"。

8.2  token接口

token功能点允许三方应用使用从授权功能点得到的授权码,来交换id  token和  access  token。

8.3  用户信息接口

三方应用可以使用access  token来访问这个接口,然后获取用户的个人信息,比如email、电话号码和地址。

8.4  可选的接口

上面三类接口是最核心的接口,所有的OP都必须提供。

OP还可以提供下面这些可选的接口:

webfinger。可以使用用户的emai地址等信息来动态发现一个OP。
provider  metadata。通过提供一个json文档,来描述当前这个provider提供的所有OpenID  connect和oAuth2的相关功能。方便三方应用查询。
三方应用注册。用来注册三方应用的restful  web  api。注册完毕后给这个应用分配client  id和  secret。
会话管理。用来判断一个已经登陆的用户是否还和OP之间保持了一个有效会话。
9,  与oAuth2.0的关系
oAuth2.0协议是用来获取对受保护的资源比如某些web  api调用所需的access  token的。OpenID  Connect则利用了oAuth2.0的这个流程来允许RP(三方应用)获取用户的身份信息。这些信息是以JWT形式进行交互的id  token。同时,OpenID  Connect还允许RP用获取id  token时由OP一并返回的access  token来进一步获取用户的个人信息,比如email、手机号码等。

下面这张图可以大致提现OpenID  Connect和oAuth2.0的关系。


图片引用自https://openid.net/connect/
上面就是本文想聊的内容,希望对大家理解OpenID  Connect有所帮助。
最新回复 (0)
返回
发新帖