OIDC身份认证
看一下官方的介绍(http://openid.net/connect/):
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and session management, when it makes sense for them.
简单来说:OIDC是OpenID Connect的简称,OIDC=(Identity, Authentication) + OAuth 2.0。它在OAuth2上构建了一个身份层,是一个基于OAuth2协议的身份认证标准协议。我们都知道OAuth2是一个授权协议,它无法提供完善的身份认证功能(关于这一点请参考[认证授权] 3.基于OAuth2的认证(译)),OIDC使用OAuth2的授权服务器来为第三方客户端提供用户的身份认证,并把对应的身份认证信息传递给客户端,且可以适用于各种类型的客户端(比如服务端应用,移动APP,JS应用),且完全兼容OAuth2,也就是说你搭建了一个OIDC的服务后,也可以当作一个OAuth2的服务来用。应用场景如图:
OIDC已经有很多的企业在使用,比如Google的账号认证授权体系,Microsoft的账号体系也部署了OIDC,当然这些企业有的也是OIDC背后的推动者。除了这些之外,有很多各个语言版本的开源服务端组件,客户端组件等等(http://openid.net/developers/certified/);
理解OIDC的前提是需要理解OAuth2,这里假设大家都有OAuth2的基础,不清楚的可以先阅读本系列的前几篇OAuth2的文章。
Core:必选。定义OIDC的核心功能,在OAuth 2.0之上构建身份认证,以及如何使用Claims来传递用户的信息。
除了上面这8个之外,还有其他的正在制定中的扩展。看起来是挺多的,不要被吓到,其实并不是很复杂,除了Core核心规范内容多一点之外,另外7个都是很简单且简短的规范,另外Core是基于OAuth2的,也就是说其中很多东西在复用OAuth2,所以说你理解了OAuth2之后,OIDC就是非常容易理解的了,我们这里就只关注OIDC引入了哪些新的东西(Core,其余7个可选规范不做介绍,但是可能会提及到)。千言万语都不如一张图,没图你说个***。
上图是官方给出的一个OIDC组成结构图,我们暂时只关注Core的部分,其他的部分了解是什么东西就可以了,当作黑盒来用。就像当初的AJAX一样,它其实并不是一个新的技术,而是结合很多已有的技术,按照规范的方式组合起来,就是AJAX。同理,OIDC也不是新技术,它主要是借鉴OpenId的身份标识,OAuth2的授权和JWT包装数据的方式,把这些技术融合在一起就是OIDC。
JSON Web Token)的自包含性,紧凑性以及防篡改机制,使得ID Token可以安全的传递给第三方客户端程序并且容易被验证。此外还提供了UserInfo的接口,用户获取用户的更完整的信息。
http://openid.net/specs/openid-connect-core-1_0.html#Terminology):
- EU:End User:一个人类用户。
- RP:Relying Party ,用来代指OAuth2中的受信任的客户端,身份认证和授权信息的消费方;
- OP:OpenID Provider,有能力提供EU认证的服务(比如OAuth2中的授权服务),用来为RP提供EU的身份认证信息;
- ID Token:JWT格式的数据,包含EU身份认证的信息。
- UserInfo Endpoint:用户信息接口(受OAuth2保护),当RP使用Access Token访问时,返回授权用户的信息,此接口必须使用HTTPS。
http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)。另外ID Token必须使用JWS进行签名和JWE加密,从而提供认证的完整性、不可否认性以及可选的保密性。一个ID Token的例子如下:
https://tools.ietf.org/html/rfc6749#section-3.2)来发放的。构建一个OIDC的Authentication Request需要提供如下的参数:
- scope:必须。OIDC的请求必须包含值为“openid”的scope的参数。
- response_type:必选。同OAuth2。
- client_id:必选。同OAuth2。
- redirect_uri:必选。同OAuth2。
- state:推荐。同OAuth2。防止CSRF, XSRF。
- EU:End User:一个人类用户。
- RP:Relying Party ,用来代指OAuth2中的受信任的客户端,身份认证和授权信息的消费方;
- OP:OpenID Provider,有能力提供EU认证的服务(比如OAuth2中的授权服务),用来为RP提供EU的身份认证信息;
- ID Token:JWT格式的数据,包含EU身份认证的信息。
- UserInfo Endpoint:用户信息接口(受OAuth2保护),当RP使用Access Token访问时,返回授权用户的信息,此接口必须使用HTTPS。
http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)。另外ID Token必须使用JWS进行签名和JWE加密,从而提供认证的完整性、不可否认性以及可选的保密性。一个ID Token的例子如下:
https://tools.ietf.org/html/rfc6749#section-3.2)来发放的。构建一个OIDC的Authentication Request需要提供如下的参数:
- scope:必须。OIDC的请求必须包含值为“openid”的scope的参数。
- response_type:必选。同OAuth2。
- client_id:必选。同OAuth2。
- redirect_uri:必选。同OAuth2。
- state:推荐。同OAuth2。防止CSRF, XSRF。
- scope:必须。OIDC的请求必须包含值为“openid”的scope的参数。
- response_type:必选。同OAuth2。
- client_id:必选。同OAuth2。
- redirect_uri:必选。同OAuth2。
- state:推荐。同OAuth2。防止CSRF, XSRF。
以上这5个参数是和OAuth2相同的。除此之外,还定义了如下的参数:
- response_mode:可选。OIDC新定义的参数(OAuth 2.0 Form Post Response Mode),用来指定Authorization Endpoint以何种方式返回数据。
- nonce:可选。ID Token中的出现的nonce就是来源于此。
- display : 可选。指示授权服务器呈现怎样的界面给EU。有效值有(page,popup,touch,wap),其中默认是page。page=普通的页面,popup=弹出框,touch=支持触控的页面,wap=移动端页面。
- prompt:可选。这个参数允许传递多个值,使用空格分隔。用来指示授权服务器是否引导EU重新认证和同意授权(consent,就是EU完成身份认证后的确认同意授权的页面)。有效值有(none,login,consent,select_account)。none=不实现现任何认证和确认同意授权的页面,如果没有认证授权过,则返回错误login_required或interaction_required。login=重新引导EU进行身份认证,即使已经登录。consent=重新引导EU确认同意授权。select_account=假如EU在授权服务器有多个账号的话,允许EU选择一个账号进行认证。
- max_age:可选。代表EU认证信息的有效时间,对应ID Token中auth_time的claim。比如设定是20分钟,则超过了时间,则需要引导EU重新认证。
- ui_locales:可选。用户界面的本地化语言设置项。
- id_token_hint:可选。之前发放的ID Token,如果ID Token经过验证且是有效的,则需要返回一个正常的响应;如果有误,则返回对应的错误提示。
- login_hint:可选。向授权服务器提示登录标识符,EU可能会使用它登录(如果需要的话)。比如指定使用用户使用blackheart账号登录,当然EU也可以使用其他账号登录,这只是类似html中input元素的placeholder。
- acr_values:可选。Authentication Context Class Reference values,对应ID Token中的acr的Claim。此参数允许多个值出现,使用空格分割。
以上是基于Authorization Code方式的OIDC的认证请求所需的参数。在OIDC的其他认证流程中也会有其他的参数或不同的参数值(稍有差异)。一个简单的示例如下
GET /authorize?response_type=code&scope=openid%20profile%20email&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
HTTP/1.1
Host: server.example.com
也可以是一个基于302的重定向方式。
http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation,验证通过后引导EU进行身份认证并且同意授权。在这一切都完成后,会重定向到RP指定的回调地址,并且把code和state参数传递过去。比如:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation和http://openid.net/specs/openid-connect-core-1_0.html#ImplicitTokenValidation)。至此,可以说用户身份认证就可以完成了,后续可以根据UserInfo EndPoint获取更完整的信息。
http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest,这里就不做详细介绍了。
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest,这里就不做详细介绍了。
Hybrid Flow则=Authorization Code Flow+Implicit Flow,也不再详细介绍了。
https://github.com/linianhui/oidc.example 。
http://openid.net/connect/
http://openid.net/connect/faq/
http://openid.net/developers/certified/
JWT : https://tools.ietf.org/html/rfc7519
JWS:https://tools.ietf.org/html/rfc7515
JWE:https://tools.ietf.org/html/rfc7516
.NET的开源实现:https://github.com/IdentityServer
视频:Identity, Authentication + OAuth = OpenID Connect
案例:
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code
https://developers.google.com/identity/protocols/OpenIDConnect
原文地址: