Oauth和oidc的关系和讲解

Oauth2.0是一套授权框架,目标是解决第三方应用如何在不获取用户密码的前提下,代表用户去访问受保护的资源。oidc是在oauth2之上的身份认证层,核心目标是让客户端能验证用户,它在 OAuth 2.0 的授权流程上,额外返回一个 ID Token

OAuth

Oauth2.0是一套授权框架,目标是解决第三方应用如何在不获取用户密码的前提下,代表用户去访问受保护的资源。oauth体系里面,有四个角色,分别是资源所有者、客户端、授权服务器、资源服务器。

资源所有者一般就是用户,是数据拥有者,有权决定是否授权,客户端是想要访问用户数据的第三方应用,比如有个工具想要读取你gayhub仓库列表的项目管理。授权服务器用于验证身份、征得同意、颁发令牌,gayhub也有oauth登录服务。资源服务用于存储受保护的api服务,如github有restapi,需要令牌,不认密码。

然后是授权模式,首先是授权码模式,这个是最安全、最常用的模式。用户需要发请请求,比如阿紫客户端点击使用github登录,重定向到授权服务器中,客户端把用户的浏览器重定向到github的授权服务器,请求用户授权。用户需要登录并授权,同意授权给客户端相应的权限。完成之后授权服务器把浏览器重定向会客户端,并在URL上带上一个授权码,客户端在后台用授权码+客户端秘钥向授权服务器换取访问令牌,客户端就可以通过访问令牌去资源服务器上请求用户的数据了。

隐式模式不推荐,它是令牌慧姐通过URL返回,容易泄漏,无法刷新。密码模式已禁止,用户需要把密码直接给客户端,从根本上违背了OAuth的设计。

客户端机密模式是服务间调用,用户无参与,客户端会以自己的身份获取令牌,用于访问自己的资源,不涉及用户。

OAuth本身留下了很多安全细节,最新实践RFC 9700明确表示强制使用PKCE,所有的客户端类型,尤其是公开客户端SPA 移动APP都需要使用PKCE来防止授权码被拦截。授权服务器必须对重定向uri进行精确的字符串匹配,不能使用通配符或者模式匹配,防止授权码被重定向到恶意地址。

注意: OAuth只负责授权,不负责认证,使用Google登录这种选项实际上是OAuth2.0 + OIDC的组合。OIDC 是 OAuth 2.0 之上的一个身份层,它额外提供了一个 ID 令牌 (ID Token) ,这是一个包含用户身份信息(如姓名、邮箱)的 JWT,用来证明用户身份,之后会讲。

为什么访问资源需要客户端秘钥,这个是为了证明客户端身份,因为授权服务器需要确认客户端是否真的是我们自己规定的客户端,如果说授权码被拦截也无所谓,有了客户端秘钥才能换令牌。

OIDC

然后我们来谈谈oidc部分,它是在oauth2之上的身份认证层,核心目标是让客户端能验证用户,它在 OAuth 2.0 的授权流程上,额外返回一个 ID Token(JWT)。

因为oauth2只会给access_token,也就是用于访问资源的访问令牌,oidc额外返回了id_token,id_token是jwt,能够包含用户信息,客户端解 id_token。然后客户端是可以验证id token里面的签名的,需要使用JWKS,我们可以通过一个get请求,去访问公钥集合:

GET https://auth.example.com/.well-known/jwks.json

{
    "keys": [
        {
            "kty": "RSA",
            "kid": "key-1",
            "use": "sig",
            "n": "...",
            "e": "AQAB"
        }
    ]
}

并且scope里面必须包含openid,不然就不是oidc。OIDC 定义了标准 scope:

scope含义返回的 claim
openid必须,表示 OIDCsub
profile基本资料name、family_name、picture 等
email邮箱email、email_verified
address地址address
phone电话phone_number、phone_number_verified

oidc的使用场景:

SSO 单点登录,用户登录一次,可以多个应用共享身份,每个应用用oidc来验证用户。比如企业sso,一个idp,多个应用。

社交登录:使用google登录,是使用oauth2.0+oidc,拿id_token->验证用户。

移动App:调用系统浏览器访问授权服务器返回id_token。然后客户端是可以验证id