认识和理解OCID

本文详细介绍了OIDC(OpenIDConnect)基于OAuth2.0的身份认证协议,包括授权码模式、隐式模式和混合模式的流程,以及涉及的安全措施,如授权请求参数和使用授权码获取accessToken的过程。
摘要由CSDN通过智能技术生成

OIDC,即OpenID Connect,它是基于OAuth 2.0的认证授权行业标准协议。它构建在OAuth 2.0之上,提供了一个身份认证层,用于用户身份的认证。OIDC允许用户数据安全地暴露给第三方,同时支持各种类型的客户端,如服务端应用、移动应用和Web应用。使用OIDC时,授权服务器会为第三方客户端提供用户的身份认证信息,确保了用户身份的验证和授权过程。OIDC与OAuth 2.0是完全兼容的,因此,部署了OIDC服务的系统也可以作为OAuth 2.0的服务来使用。


概述

当你的用户需要访问服务器上受保护资源的时候,例如用户订单数据,用户购物车等,需要携带id_token。
id_token是用户的身份标识,就像身份证一样。id_token是一个JWT Token

如果请求没有携带id_token,或者携带的id_token不合法,则表示本次请求认证不通过。

你为其他人提供身份服务,其他应用需要从你的服务器获取用户信息。

比如github提供身份服务,其他应用可以向github索要用户的信息,完成用户在他们平台的注册,即三方登录。其实质是,在用户同意第三方应用访问该用户在授权服务器上的信息的前提下,授权服务器生成一个Access Token给第三方,只要第三方拥有这个token,就能代表用户访问授权服务器上的用户身份信息。

OIDC流程

既然需要认证、授权,那你的服务器,第三方服务器、用户这三者之间如何通信呢?如何颁发token?需要遵守怎样的规范?OIDC就是这样一套规范,其应用广泛,轻量简单,基于OAuth 2.0,既可以用于授权,也可以用于身份认证。

access_token用于授权,id_token用户认证。

授权码模式

授权码模式是最常用的OIDC流程,如下图所示:
在这里插入图片描述
描述如下:

  • 第三方发起授权请求
  • 授权服务器询问用户是否同意授权,要求用户输入用户名和密码。
  • 授权服务器返回一个授权码给第三方应用(前端或后端都行)。
  • 第三方应用后端携带这个授权码向授权服务器请求token。
  • 授权服务器返回id_token和access_token。

在上述流程中,授权请求里面的scope参数中是带有openid的,因此最后返回的token包含id_token。如果不带openid呢?则最后返回的只有accessToken,而没有id_token。

隐式模式

当发起授权请求时query参数中response_type不为code的时候,则表示使用隐式模式。

在这种模式下,response_type可以为tokenid_tokenid_token token

隐式模式可以在一次请求中就获取到token,而不需要额外的返回授权码再通过授权码获取token这两步。返回的token中包含什么则取决于response_type,可以只有access token或者只有id_token或者两者都包含。

隐式模式流程如下:
在这里插入图片描述
可以看出,隐式模式最为简单直接,但是在安全性上不如授权码模式,因为可能会在前端暴露Access Token。隐式模式要求回调地址必须为https。

从流程图可以看出,当授权服务器要求用户授权后,授权服务器需要主动回调客户端。所谓的回调地址就用在这里。

混合模式

混合模式的意思是发起授权请求后,既返回授权码又返回AccessToken或ID Token。

混合模式要求query参数response_type=code id_tokenresponse_type=code tokenresponse_type=code id_token token

这三种形式的混合模式流程如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

response_type是第一次用户认证之后的返回值,scope是获取用户信息时的返回值。

授权码模式的安全性

OIDC授权码模式的认证流程中涉及三方:用户、OIDC服务器(OP, OIDC Provider)、应用服务器(SP, Service Provider)。

SP、用户、OP的交互目的分为以下几点:

  1. SP希望拿到一个可信的身份断言,从而让用户登录。
  2. SP发起登录,会跳转到OP的认证页面,OP让用户登录,并授权自己的信息,然后OP将一个授权码code发给SP。
  3. SP收到授权码之后,结合Client ID和Client Secret 到OP换取该用户的access_token。
  4. SP利用access_token到OP去获取用户的相关信息,而从得到一个可信的身份断言,让用户登录。

OIDC协议中,用户登录成功后,OIDC认证服务器会将用户的浏览器回调到一个回调地址,并携带一个授权码code。这个授权码一般有效期10分钟且一次有效,用后作废。

后端收到授权码code之后,需要使用Client Id + Client Secret + Code 去OIDC认证服务器换取用户的access_token。在这一步,实际上OIDC Server对OAtuth Client进行了认证,能够确保来OIDC认证服务器获取access_token的机器是可信任的,而不是任何一个人拿到code之后都能来OIDC认证服务器换取token。即使code被黑客获取到,如果他没有Client Id + Client Secret也无法使用。就算有,也要和真正的应用服务器竞争,因为code一次有效,用后作废,加大了攻击难度。

授权请求参数

在上文中经常提到scope和response_type参数,事实上,授权请求中有如下Query Parameters参数:

参数名类型说明
client_id(必填)string应用id
redirect_uri(必填)sting回调地址,授权服务器返回授权码时使用
scope(必填)sting指定客户端请求token时所需权限,如果是授权码模式则必须包含openid;还可以指定profile和offline_access,分别表示要获取用户基本文件信息和获取刷新令牌;多个scope参数用空格分隔。id_token解码后的内容会包括scope对应的用户信息相关字段
response_type(必填)sting标识登录成功后OP要返回的信息
prompt(可选)sting可以为 none,login,consentselect_account,指定 OP 与 End-User 的交互方式,如需 refresh_token,必须为 consent
state(必填)string一个随机字符串,用于防范CSRF攻击,如果response中的state值和请求发送之前设置的state不同,则说明受到攻击
nonce(可选)string一个随机字符串,用于防范Replay攻击

通过授权码获取访问令牌accessToken时,通常需要如下参数:

参数名类型说明
grant_type(必填)string指定授权类型为 “authorization_code”,表示使用授权码进行访问令牌的获取
code(必填)sting授权码
redirect_uri(必填)sting回调地址,与授权请求时提供的回调地址必须一致
client(必填)sting客户端标识符
client_secret(可选)sting客户端密钥

Token验证

在上文中介绍了几种从授权服务器获取OIDC token的方式。但拿到token后,一般来说,还需要校验token的合法性,以确保token未被篡改、未过期,并且是由可信的授权服务器签发,主要验证签名和声明。

首先需要将token转换成JWT,其中包含了签名,key id,jwt的签发者,audience和过期时间等。

验证签名时需要从远程获取Json Web Key Set,从该keySet中获取key id对应的JWK,再根据签名算法来构建签名验证器,最后调用JWT的verify方法来验证签名。

除了签名之外,还需要验证token没有过期,token签发者和audience等是合法的。下面是代码示例:


// 先将字符串类型的Json Web Token 转换成签名的token
SignedJWT signedJWT = SignedJWT.parse(token);

// 获取远程Json Web Key Set
RemoteJWKSet<JWKSecurityContext> remoteJWKSet = new RemoteJWKSet<>(new URL("https://example.com/.well-known/jwks.json"));

// 从signedJWT中获取key的标识
String kid = signedJWT.getHeader().toJSONObject().get(Claim.KEY_ID.getValue()).toString()

// 从远程JWKS中获取JWK
JWKMatcher jwkMatcher = new JWKMatcher.Builder().keyID(kid).build();
JWK jwk = remoteJWKSet.get(new JWTSelector(jwkMatcher), null).stream().findFirst();
// 构建JWS验证器
JWSVerifier verifier = new RSASSAVerifier(RSAKey.parse(jwk.toJSONString()).toRSAPublicKey());

// 验证签名、有效期和声明
bool result = signedJWT.verify(verifier) && signedJWT.getJWTClaimsSet().getExpirationTime().toInstant().isAfter(Instant.now())
&& Objects.equals("myIssuer", signedJWT.getJWTClaimsSet().getIssuer())
&& signedJWT.getJWTClaimsSet().getAudience().contains(CLIENTID);

参考资料

[1]https://old-docs.authing.cn/authentication/oidc/understand-oidc.html

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值