首先介绍几个易混淆的概念。
认证与授权
认证(Authentication):通过认证以确定用户身份,认证可以理解为用户登录过程。
授权(Authorization):给用户分配可权限,以确定用户可访问的资源范围。授权的前提是要确认用户身份,即先认证,再授权。
OpenID、OpenID Connect、OAuth2.0
OpenID、OpenID Connect:提供第三方认证的协议规范,第三方认证也可以理解为单点登录SSO,即一个认证服务和多个业务应用。用户在认证中心登录,业务应用通过认证中心接口获取用户身份信息,典型场景为企业内部Web系统集成单点登录,典型的有CAS。
OAuth2.0:向第三方系统提供授权(访问自身)服务的协议规范。通过向第三方系统提供Token,以便在不向第三方系统提供自身密码的情况下,授权第三方系统访问自身的部分服务。
OpenID vs OpenID Connect
OpenID:由OpenID基金会维护的第三方认证规范,存在如下缺点:
- 以URI为用户唯一标识,用户难以记忆
- 第三方应用必须是网站,没有提供API,不支持移动应用
- 不支持健壮的加密和签名
OpenID Connect:基于OAuth2.0实现的用户认证规范。相对OpenID提供了如下增强特性。
- 提供可扩展性,运行人们通过任何OpenID Connect Provider进行身份验证,而不是仅限于Google、Facebook等主流IDP。
- 电子邮件作为用户标识,便于用户记忆。
- 允许客户端动态注册,减轻管理员显示注册设备和网站的工作量。
一个授权服务如何为第三方提供认证服务?
OpenID Connect对OAuth2.0接口进行了扩展,通过在协议中扩展身份认证所需的ID Token字段,增加UserInfo Endpoint接口,向第三方应用提供身份认证服务。
- 用户执行OAuth2.0的授权流程后,第三方应用获得Access Token和附加的ID Token,ID Token包含基本的用户身份信息,可用于身份认证。
- 如果需要更详细用户信息,第三方应用通过Access Token,从认证服务UserInfo Endpoint接口获取用户信息。
- 第三方应用可以把ID Token和UserInfo信息作为认证用户的用户信息。
OpenID Connect基础
OpenID Connect(简称OIDC)是一种安全认证机制,第三方应用连接到身份认证服务器(Identify Service)获取用户信息,并把这些信息以安全可靠的方式返回给第三方应用。
OAuth2.0通过Access Token作为向第三方应用授权访问自身资源的凭证。OpenID Connect对OAuth2.0进行协议进行了扩展,通过扩展的ID Token字段,提供用户基础身份信息,ID Token使用JWT(JSON Web Token)格式进行封装,提供自包含性、防篡改机制,可以安全的传递给第三方应用程序并容易被验证。除了ID Token,还可以通过Access Token从认证服务的UserInfo Endpoint接口获取更详细的用户信息。
相关概念
End User(EU):被认证的用户。
Relying Party(RP):OpenID Connect客户端,即需要认证服务的第三方应用,身份认证服务的消费者。
OpenID Provider(OP):提供身份认证的服务,为RP提供EU的身份认证信息,又称Identify Provider。
ID Token:JWT格式封装的EU用户身份认证信息JSON。
UserInfo Endpoint:查询用户信息接口,返回当前Access Token对应授权用户的信息。
OpenID Connect认证模式
OAuth2.0提供了四种授权模式,分别为授权代码模式(Authorization code)、隐含模式(Implicit)、资源所有者密码凭据模式(Resource Owner Password)和客户端凭据模式(Client Credentials)。由于资源所有者密码凭据模式直接向第三方应用提供了密码,客户端凭据模式直接信任第三方应用,这两种模式下无需再进行附加认证。所以OpenID Connect提供了授权代码模式(Authorization code)、隐含模式(Implicit)两种认证模式,还有一种混合模式(两种模式的混合),认证的流程和OAuth2.0的流程基本一致,附加了ID Token和UserInfo Endpoint接口。
认证流程概览
详细流程说明请参考 OpenID Connect Core 1.0规范
+--------+ +--------+
| | | |
| |---------(1) AuthN Request-------->| |
| | | |
| | +--------+ | |
| | | | | |
| | | End- |<--(2) AuthN & AuthZ-->| |
| | | User | | |
| RP | | | | OP |
| | +--------+ | |
| | | |
| |<--------(3) AuthN Response--------| |
| | | |
| |---------(4) UserInfo Request----->| |
| | | |
| |<--------(5) UserInfo Response-----| |
| | | |
+--------+ +--------+
The OpenID Connect protocol, in abstract, follows the following steps.
- The RP (Client) sends a request to the OpenID Provider (OP).
- The OP authenticates the End-User and obtains authorization.
- The OP responds with an ID Token and usually an Access Token.
- The RP can send a request with the Access Token to the UserInfo Endpoint.
- The UserInfo Endpoint returns Claims about the End-User.
认证代码模式(### Authorization Code)
由于OpenID Connect的认证流程和OAuth2.0的授权流程基本一致,此处不再介绍详细的流程,只说明差异部分,关于OAuth2.0的授权流程,可以参考 OAuth 2.0认证框架介绍。
认证代码模式的整体认证步骤如下:
- Client准备认证相关的请求参数。
- Client向授权服务器(Authorization Server)请求认证。
- 授权服务器认证(登录)用户。
- 用户确认给Client授权并确认。
- 授权服务器把用户重定向回Client,URL中携带授权代码。
- Client(服务器端)通过授权代码,向Token Endpoint发送请求。
- Token Endpoint接口返回ID Token和Access Token。
- Client校验ID Token,并从中提取用户的身份标识(Subject Identifier)。
差异点:
- 获取认证代码请求(第2步)中,scope必须包含
openid
字段。
HTTP/1.1 302 Found
Location: https://server.example.com/authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
- Token Endpoint接口返回数据中,和OAuth2.0比,增加了ID Token字段。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"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"
}
其他步骤基本一致。
ID Token
ID Token是JWS(JSON Web Signature)格式的字符串,相关规范可参考 JSON Web Signature草案,JWS字符串有三部分组成,分别为JWS Protected Header、JWS Payload、JWS Signature,三部分内容分别Base64编码后通过点(.)拼接,拼接公式如下:
BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
JWS可以通过JWS Signature来校验数据的完整性,但不提供机密性。
JWS Payload是ID Token的内容部分,是一个JSON对象,包括如下字段:
字段 | 含义 |
---|---|
iss | (Issuer Identifier)ID Token颁发者的标识符,一般为认证服务器的URL。 |
sub | (Subject Identifier)认证用户(End User)标识符,全局唯一。 |
aud | (Audience(s))ID Token的受众,必须包含第三方应用的client_id。 |
exp | (Expiration time)Token过期时间。 |
iat | (Issued At Time)JWT生成时间。 |
nonce | 随机数,防重放攻击。 |
auth_time | (Authentication Time)用户认证发送时间。 |
acr | (Authentication Context Class Reference)表示一个认证上下文引用值,用以标识认证上下文类。 |
amr | (Authentication Methods References)一组认证方法。 |
azp | (Authorized party)结合aud使用,只有在被认证的一方和受众(aud)不一致时才使用此值,一般情况下很少使用。 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。