搜 索

OIDC从入门到放弃

  • 406阅读
  • 2023年04月02日
  • 0评论
首页 / Java/Scala/C / 正文

OIDC是啥

OIDC 是 OpenID Connect 的缩写,是一个建立在 OAuth 2.0 协议之上的身份验证和授权协议。它旨在提供一个安全、标准化的方式,让用户在不同的应用程序之间进行身份验证和授权,从而实现单点登录(Single Sign-On,SSO)。
OAuth2是一个授权(authorization)的开放协议,OAuth2只解决了授权问题,没有实现认证部分,往往需要添加额外的API来实现认证。而OpenID呢,是一个认证(authentication )的协议。就好像一把钥匙可以打开你的家门,OAuth做的事情就是无论谁只要拿着这个钥匙就打开你的家门,OIDC做的是必须是你本人拿着这个钥匙才能打开你的家门,其他人不行。

OIDC与OAuth2的关系

OIDC是OAuth2的超集,它是基于OAuth2+OpenID整合的新的认证授权协议。OAuth2是一个授权(authorization)的开放协议,OAuth2只解决了授权问题,没有实现认证部分,往往需要添加额外的API来实现认证。而OpenID呢,是一个认证(authentication )的协议。

与传统的OpenID 协议不同,OIDC 使用了 OAuth 2.0 协议中的令牌(Token)机制,使得用户的身份验证和授权信息能够得到更好的保护。OIDC 还引入了 ID Token 的概念,这是一个JSON Web Token(JWT)格式的令牌,包含了有关用户身份的基本信息,例如用户的唯一标识符、姓名、电子邮件地址等等。

通过 OIDC,客户端应用程序可以通过重定向用户到 OIDC Provider 进行身份验证和授权,然后获得一个 Access Token,从而可以访问资源服务器上受保护的资源。OIDC 还支持多种 OAuth 2.0 授权模式,包括授权码模式、隐式授权模式、密码模式等等,以满足不同场景下的需求。

总之,OIDC 提供了一种灵活、安全、易于使用的方式,让不同的应用程序之间可以实现单点登录和资源共享,从而提高了用户体验和数据安全性。

OIDC中的token

OIDC中主要是3种token:Access Token、Refresh Token和Id Token,其中Access Token和Id Token都属于JWT(Json web token),其有效期较短,Refresh Token是用于获取新的Access和Id Token。

什么是JWT

JWT代表JSON Web Token,是一种开放标准的身份验证和授权令牌。JWT由三个部分组成:头部header、载荷payload和签名signature。

头部通常包含令牌的类型和所使用的加密算法。载荷是令牌的主体部分,包含所需的声明,例如用户ID、角色和权限等信息。这些声明是编码成JSON格式的键值对。签名是由头部、载荷和一个密钥生成的哈希值,用于验证令牌的真实性和完整性。

JWT头和Payload都可以base64解码为json格式字符串,signature为验证签名防篡改使用。

Access Token起什么作用

accessToken(访问令牌)是用于访问资源服务器上受保护资源的令牌。它通常包含授权信息,例如允许客户端应用程序访问哪些资源的范围。accessToken通常在OAuth 2.0授权流程中使用,并由OAuth提供者返回给客户端应用程序。

Id Token起什么作用

idToken(身份验证令牌)是一个 JSON Web Token(JWT),包含有关用户身份验证信息的声明。它通常包含用户的身份信息,如用户名、电子邮件地址、身份验证时间戳等。idToken被用于验证用户身份,通常由身份提供者(如OAuth提供者)返回给客户端应用程序。

Refresh Token起什么作用

由于idToken和access token都被设计为有效期较短,可能有效期是几分钟到几十分钟不等,而refresh token有效期都有几十天到几百天,在id token或access token过期时使用refresh token来刷新有效期。

用户在初次认证时Refresh Token会和AccessToken、Id Token一起返回。你的应用必须安全地存储Refresh Token,它的重要性和密码是一样的,因为Refresh Token能够一直让用户保持登录。

应用携带Refresh Token向Token端点发起请求时,Authing每次都会返回相同的Refresh Token和新的AccessToken、IdToken,直到Refresh Token过期。

案例

案例如下:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJ4R01uczd5cmNFckxiakNRVW9US1MiLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ1Mzc4NjksImV4cCI6MTU1NDU0MTQ2OSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBvZmZsaW5lX2FjY2VzcyBwaG9uZSBlbWFpbCIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.wX05OAgYuXeYM7zCxhrkvTO_taqxrCTG_L2ImDmQjMml6E3GXjYA9EFK0NfWquUI2mdSMAqohX-ndffN0fa5cChdcMJEm3XS9tt6-_zzhoOojK-q9MHF7huZg4O1587xhSofxs-KS7BeYxEHKn_10tAkjEIo9QtYUE7zD7JXwGUsvfMMjOqEVW6KuY3ZOmIq_ncKlB4jvbdrduxy1pbky_kvzHWlE9El_N5qveQXyuvNZVMSIEpw8_y5iSxPxKfrVwGY7hBaF40Oph-d2PO7AzKvxEVMamzLvMGBMaRAP_WttBPAUSqTU5uMXwMafryhGdIcQVsDPcGNgMX6E1jzLA",
  "expires_in": 3600,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjIyMTIxIiwiYXRfaGFzaCI6Ik5kbW9iZVBZOEFFaWQ2T216MzIyOXciLCJzaWQiOiI1ODM2NzllNC1lYWM5LTRjNDEtOGQxMS1jZWFkMmE5OWQzZWIiLCJhdWQiOiI1Y2E3NjVlMzkzMTk0ZDU4OTFkYjE5MjciLCJleHAiOjE1NTQ1NDE0NjksImlhdCI6MTU1NDUzNzg2OSwiaXNzIjoiaHR0cHM6Ly9hdXRoaW5nLmNuIn0.IQi5FRHO756e_eAmdAs3OnFMU7QuP-XtrbwCZC1gJntevYJTltEg1CLkG7eVhdi_g5MJV1c0pNZ_xHmwS0R-E4lAXcc1QveYKptnMroKpBWs5mXwoOiqbrjKEmLMaPgRzCOdLiSdoZuQNw_z-gVhFiMNxI055TyFJdXTNtExt1O3KmwqanPNUi6XyW43bUl29v_kAvKgiOB28f3I0fB4EsiZjxp1uxHQBaDeBMSPaRVWQJcIjAJ9JLgkaDt1j7HZ2a1daWZ4HPzifDuDfi6_Ob1ZL40tWEC7xdxHlCEWJ4pUIsDjvScdQsez9aV_xMwumw3X4tgUIxFOCNVEvr73Fg",
  "refresh_token": "WPsGJbvpBjqXz6IJIr1UHKyrdVF",
  "scope": "openid profile offline_access phone email",
  "token_type": "Bearer"
}

其中expires_in是指access_token和id_token的有效期,scope是指定access_token能够访问的资源类型,token_type一般为Bearer,access_token和id_token的值需要客户端存储下来,refresh_token是长期有效的,需要加密储存。

OIDC的认证流程

OIDC 的实现方式主要分为两个角色:客户端应用程序(即RP)和 OIDC Provider(即OP)。

客户端应用程序是指需要使用 OIDC 进行身份验证和授权的应用程序,例如 Web 应用程序、移动应用程序等等。客户端应用程序需要使用 OIDC 协议与 OIDC Provider 进行交互,以获得访问资源服务器所需的 Access Token。

OIDC Provider 是指实现了 OIDC 协议的身份验证和授权服务器,它负责验证客户端应用程序的身份,向客户端应用程序发放 Access Token,并对访问资源服务器的请求进行授权。

OIDC 的实现过程通常如下:

客户端应用程序重定向用户到 OIDC Provider,以进行身份验证和授权。

用户在 OIDC Provider 上进行身份验证,并同意客户端应用程序访问其受保护的资源。

OIDC Provider 向客户端应用程序颁发一个 ID Token 和一个 Access Token。

客户端应用程序使用 Access Token 请求访问资源服务器上的受保护资源。

资源服务器接收到请求后,使用 Access Token 来验证客户端应用程序的身份,并根据 OIDC Provider 的授权规则来判断是否允许客户端应用程序访问该资源。

需要注意的是,OIDC Provider 的实现通常需要依赖于 OAuth 2.0 协议,因为 OIDC 建立在 OAuth 2.0 协议之上。OIDC Provider 还需要提供 .well-known/openid-configuration URL 路径,用于存放其元数据信息,以方便客户端应用程序获取相关配置信息。

Oidc 授权模式

Oidc有三种模式 Authorize code mode, implict mode, hybrid mode,他们三种模式对于访问流程和访问数据有所差异。Authorization Code flow是最常见的模式,和oauth2相同。Implicit是无需/token接口,直接返回的一种模式。而Hybrid方式混合了前两种模式。

Authorization code flow

Authorization code flow

Implicit flow

隐式模式适合不能安全存储密钥的场景(例如前端浏览器)。在隐式模式中,应用不需要使用 code 换 token,无需请求 /token 端点,AccessToken 和 IdToken 会直接从认证端点返回。

因为隐式模式用于不能安全存储密钥的场景,所以隐式模式不支持获取 Refresh Token。
Implicit flow

Hybrid flow

在某些场景你可能既希望直接从认证端点获取 token,又能获取授权码 code 用于后续获取 refresh token,建议使用混合模式。在混合模式中,应用会收到 token 与 code。应用可以选择将 code 发送给后端服务,用于从 /token 端点获取用户的 AccessToken、IdToken、refresh token。
Hybrid flow

不同模式的特点

特性授权码模式隐式模式混合模式
所有 token 全部从授权端点返回noyesno
所有 token 都从 token 端点返回yesnono
token 不会暴露给前端yesnono
客户端可以被 OP 认证yesnoyes
可以刷新 tokenyesnoyes
一次交互noyesno
必须服务器-服务器通信yesnovaries

response_type值对应的不同模式

客户端想要访问哪种模式,是由authorize请求中的response_type值类型对应的,其对应关系如下:

"response_type" valueFlow
codeAuthorization Code Flow(授权码模式)
id_tokenImplicit Flow(隐式模式)
id_token tokenImplicit Flow(隐式模式)
code id_tokenHybrid Flow(混合模式)
code tokenHybrid Flow(混合模式)
code id_token tokenHybrid Flow(混合模式)

服务端需要根据该值做出正确的响应。

OIDC的实现方式

使用 Spring Security:Spring Security 提供了对 OIDC 的支持,可以通过添加 spring-security-oauth2-client 和 spring-security-oauth2-jose 两个依赖项来实现 OIDC。需要配置 OIDC Provider 的信息,并在 WebSecurityConfigurerAdapter 中配置 OAuth2LoginConfigurer 以启用 OIDC 支持。

使用 Pac4j:Pac4j 是一个专注于身份验证和授权的开源框架,它提供了对多种身份验证和授权协议的支持,包括 OIDC。可以通过添加 pac4j-oidc 依赖项来实现 OIDC 支持,并在 WebSecurityConfigurerAdapter 中配置 SecurityFilterChain,包括在其中添加 OIDC 认证逻辑。

使用 OpenID Connect SDK:OpenID Connect SDK 是一个开源的 Java 实现,支持 OIDC 和 OAuth 2.0。可以通过添加 openid-connect-sdk 依赖项来实现 OIDC 支持,并使用 SDK 中提供的 API 来配置和处理 OIDC 相关的流程。

使用其他第三方库:还有一些其他的第三方库也提供了对 OIDC 的支持,例如 Nimbus JOSE + JWT 和 Apache CXF 等等。

接入OIDC服务

有很多网站提供的oidc授权的服务,比如国外的auth0,国内的authing,在做集成oidc client测试时个人是基于authing来做的。而对于提供oidc服务,可以使用spring-security-oauth2-authorization-server来使用,它只提供了基础的接入方式,若需要使用

.well-known/openid-configuration

.well-known/openid-configuration 是一个 URL 路径,它用于存放 OpenID Connect Provider(OIDC)的元数据。OIDC 是一个建立在 OAuth 2.0 协议之上的身份验证和授权协议,旨在提供一个统一的方式来让用户登录不同的应用程序。

这个 URL 路径返回一个 JSON 格式的文件,其中包含了 OIDC Provider 的元数据信息,例如它支持的 OAuth 2.0 授权模式、支持的加密算法、ID Token 的签名算法等等。这些元数据信息可以帮助客户端应用程序(例如 Web 应用程序或移动应用程序)了解 OIDC Provider 的配置和功能,以便正确地与其进行交互。

jwks

jwks是一个提供证书的服务,client可以访问jwks获取对应的公钥来做id token和access token的验签。

github项目

个人编写了一个简单案例,可提供最基本的oidc鉴权服务。
Oidc Provider
Oidc Client

总结

OIDC在实际应用中具有很高的实用性,主要体现在以下几个方面:
安全性:OIDC使用JWT来传递身份验证信息,并提供了签名和加密等内置安全特性,可以保证用户身份信息的安全性。
标准化:OIDC提供了标准化的身份验证协议,使得开发人员可以在不同平台和应用程序之间共享身份验证信息,提高了开发效率和应用程序的互操作性。
用户控制:OIDC允许用户更好地控制和管理其个人信息,可以根据自己的需要授权应用程序访问特定的资源。
扩展性:OIDC具有良好的扩展性,可以适应不同的应用场景,包括单页应用程序、移动应用程序和Web API等。
综上所述,OIDC具有良好的实用性,适用于各种身份验证和授权场景,并已被广泛应用于实际开发中。

参考资料

OpenId 1.0标准OIDC 与 OAuth2.0 综述选择OIDC授权模式什么是idToken

评论区
暂无评论
avatar