Skip to content

OAuth2模型介绍

OAuth是一个开放标准,该标准允许用户让第三方应用访问该用户在某一个网站上存储的私密资源(如头像,照片,视频等),并且在这个过程中无须将用户名和密码提供给第三方应用,通过令牌(Token)可以实现这个功能,每一个令牌授权一个特定的网站在特定的时段内允许特定的资源。

wechat-login

举个例子说明一下,比如用户想在微信小程序中登录我们的应用,那么我们的应用就要访问用户在微信服务器上的一些基本信息,比如手机号,OpenId这些,但是这些信息需要用户的授权,如果用户把自己的微信帐号密码告诉我们的应用,那么我们就可以拿到用户在微信服务器上的所有数据了,这种授权方式很明显就不安全,所以就引入OAuth这种协议,现在支持最新OAuth2.1协议。

WARNING

微信小程序登录这种场景跟常用的OAuth协议有些区别,这是微信自己的协议。

接下来我们看一下OAuth的几种授权模式。

授权码模式

授权码模式适合应用具备后端服务器的场景。授权码模式要求应用必须能够安全存储密钥,用于后续使用授权码换 Access Token。授权码模式需要通过浏览器与终端用户交互完成认证授权,然后通过浏览器重定向将授权码发送到后端服务,之后进行授权码换 Token 以及 Token 换用户信息。

oauth2-server-architecture

隐式模式

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

WARNING

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

隐式模式

密码模式

密码模式适用于你既掌握应用程序又掌握应用所需资源的场景。密码模式要求应用能够安全存储密钥,并且能够被信任地存储资源所有者的账密。一般常见于自家应用使用自家的资源。密码模式不需要重定向跳转,只需要携带用户账密访问 Token 端点。

密码模式

客户端模式

客户端模式用于进行服务器对服务器间的授权(M2M 授权),期间没有用户的参与。你需要创建编程访问账号,并将 AK、SK 密钥对交给你的资源调用方。

WARNING

客户端模式不支持 Refresh Token。

客户端

OIDC

OpenID Connect协议,简称OIDC,在Oauth2的基础上,增加了Id Token,能够认证用户并完成资源授权。在可以选择OIDC的情况下,应该选择OIDC。

在 OIDC 规范 (opens new window)中,有些名词与 OAuth 2.0 有区别:

  • OpenID Provider,指授权服务器,负责签发 Id Token。Authing是 OpenID Provider。
  • 终端用户,Id Token 的信息中会包含终端用户的信息。
  • 调用方,请求 Id Token 的应用。
  • Id Token 由 OpenID Provider 颁发,包含关于终端用户的信息字段。
  • Claim 指终端用户信息字段。

ID Token

ID Token本质上是一个JWT Token,包含了该用户身份信息相关的key/value键值对,例如:

{
   "iss": "https://server.example.com",
   "sub": "24400320", // subject 的缩写,为用户 ID
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "auth_time": 1311280969,
   "acr": "urn:mace:incommon:iap:silver"
}

JWT

JSON Web Token (JWT,RFC 7519 (opens new window)),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。

JWT

想要解析JWT字符串,可以访问这个网站

什么是JWT

Access Token

Access Token 用于基于 Token 的认证模式,允许应用访问一个资源 API。用户认证授权成功后,Authing 会签发 Access Token 给应用。应用需要携带 Access Token 访问资源 API,资源服务 API 会通过拦截器查验 Access Token 中的 scope 字段是否包含特定的权限项目,从而决定是否返回资源。

如果你的用户通过社交账号登录,例如微信登录,微信作为身份提供商会颁发自己的 Access Token,你的应用可以利用 Access Token 调用微信相关的 API。这些 Access Token 是由社交账号服务方控制的,格式也是任意的。

Opaque Access Token

Opaque Access Token 是一串随机字符串,从中不能获取到任何信息,你需要将它发送到服务器进行解析。只能通过将 Token 发到服务器的方式来验证 Opaque Access Token。

JWT Access Token

JWT 全称为 JSON Web Token (opens new window),遵循 JWT 标准。JWT 中包含了主体、受众、权限、颁发时间、过期时间、用户信息字段等内容且具备签名,不可篡改。因此无需发送到服务器,可以本地验证。Authing 在大多数情况下使用此种格式的 Token。

Access Token 示例

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjF6aXlIVG15M184MDRDOU1jUENHVERmYWJCNThBNENlZG9Wa3VweXdVeU0ifQ

解析后的内容

解析后的内容:

{
  "jti": "3YByyfvL0xoMP5wpMulgL",
  "sub": "60194296801dc7bc2a1b2735", // subject 的缩写,为用户 ID
  "iat": 1612444871,
  "exp": 1613654471,
  "scope": "openid email message",
  "iss": "https://steam-talk.authing.cn/oidc",
  "aud": "60193c610f9117e7cb049159"
}

Refresh Token

AccessToken和IdToken是 JSON Web Token (opens new window),有效时间通常较短。通常用户在获取资源的时候需要携带AccessToken,当AccessToken过期后,用户需要获取一个新的 AccessToken。

Refresh Token用于获取新的AccessToken。这样可以缩短AccessToken的过期时间保证安全,同时又不会因为频繁过期重新要求用户登录。

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

以下是 Token 端点返回的 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"
}

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

本篇文章参考: https://docs.authing.cn/v2/concepts/oidc/oidc-overview.html