鉴权方案

作者: shaokang 时间: August 9, 2024字数:4878

鉴权方案

互联网系统,安全问题一直是一个比较大的问题,所以鉴权方案也是互联网系统开发中比较重要的一个环节。下面介绍几种鉴权方案。

1. HTTP 基本认证

允许 HTTP 用户代理在请求时,通过用户提供用户名和密码的方式,实现对用户身份的验证。更多内容

用户名和密码都是通过 base64 编码后通过 HTTP 明文传输的,安全性较低。线上网络基本不会用这种方式。

由于 HTTP 协议是无状态的,服务端无法识别用户身份,所以需要借助 Cookie 来保存用户身份信息。在服务端创建 Session,将用户身份信息保存到 Session 中。服务端校验请求中的用户标识是否存在 Session 中,如果有表示认证成功。

认证流程:

  1. 客户端:向服务器发送登录信息用户名/密码来请求登录校验;
  2. 服务器:验证登录的信息,验证通过后自动创建 Session(将 Session 保存在内存中,也可以保存在 Redis 中),然后给这个 Session 生成一个唯一的标识字符串会话身份凭证  session_id(通常称为  sid),并在响应头  Set-Cookie  中设置这个唯一标识符;

    注:可以使用签名对 sid 进行加密处理,服务端会根据对应的 secret  密钥进行解密 (非必须步骤)

  3. 客户端: 收到服务器的响应后会解析响应头,并自动将  sid  保存在本地 Cookie 中,浏览器在下次 HTTP 请求时请求头会自动附带上该域名下的 Cookie 信息;
  4. 服务器:接收客户端请求时会去解析请求头 Cookie 中的  sid,然后根据这个  sid  去找服务端保存的该客户端的  sid,然后判断该请求是否合法;

优点:

  • 简单易用
  • Session 保存在服务端,方便管理

缺点:

  • 安全性低,sid 保存在客户端,很容易被窃取
  • Session 存储在服务端,增大服务端开销

3. Token 认证

客户端访问服务器时,验证通过后服务端会为其签发一张令牌,之后,客户端就可以携带令牌访问服务器,服务端只需要验证令牌的有效性即可。

认证流程:

  1. 客户端:输入用户名和密码请求登录校验;
  2. 服务器:收到请求,验证用户名与密码;验证成功后,服务端会签发一个 Token 并把这个 Token 发送给客户端;
  3. 客户端:收到 Token 后存储起来,一般会放在 localStorage 或 sessionStorage 里;
  4. 客户端:下次向服务端请求资源,将 Token 附带于 HTTP 请求头 Authorization 字段或者其它方式发送给服务端;
  5. 服务器:收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据,否则拒绝返还(401);

优点:

  • 服务端无状态,可扩展性高
  • 安全性高,避免 CSRF 攻击
  • 支持跨域访问

缺点:

  • 占用带宽,比 session_id 更大,消耗更多流量
  • 性能问题,如果不用访问数据库或远程服务进行权限校验,但对 token 加解密更耗性能。

与 Session-Cookie 的区别
用户标识存储在前端,服务端根据规则校验合法即可;存储方式多样,不再限制于 Cookie;安全性更高。

4. JWT 认证

JWT(JSON Web Token)是 Auth0 提出的通过对 JSON 进行加密签名来实现授权验证的方案。登录成功后将相关信息组成 JSON 对象,然后对这个对象进行某种方式的加密,返回给客户端,客户端在下次请求时带上这个 Token,服务端再收到请求时校验 token 合法性。

JWT 由三部分组成: Header 头部、 Payload 负载 和 Signature 签名。

认证流程与 Token 认证类似,只是不需要查询数据库。

优点:

  • 不需要服务端保存用户状态,服务端无状态
  • JWT 载荷可以存储常用信息,用于信息交换,可以减少查询数据库的次数

缺点:

  • 到期问题:一旦签发,在到期之前始终有效。
  • 加密问题:仅 Base64 编码,不能存储敏感信息

5. 单点登录

单点登录(Single Sign-on),是指在多系统应用群中登录单个系统,便可在其他所有系统中得到授权而无需再次登录。

同域单点登录

  1. 客户端:用户访问某个子系统时(例如 a.baidu.com),如果没有登录,则跳转至 SSO 认证中心提供的登录页面进行登录;
  2. 服务端:登录认证后,服务端把登录用户的信息存储于 Session 中,并且附加在响应头的  Set-Cookie  字段中,设置 Cookie 的 Domain 为 .baidu.com ;
  3. 客户端:用户访问同域名的系统 B,浏览器会携带主域名 Domain 下的 Cookie 给服务器,此时服务端就可以通过该 Cookie 来验证登录状态了;

跨域单点登录

跨域登录,依赖 CAS 中央授权服务。认证流程更多见 CAS-Protocol

  1. 客户端:访问系统 A 用户未登录,重定向至 CAS 认证服务(sso.com);
  2. CAS 认证服务:发现请求 Cookie 中没有携带登录的票据凭证(TGC),判定用户未登录,重定向用户页面至 CAS 的登录界面,用户在 CAS 的登录页面上进行登录操作;
  3. 客户端:输入用户名密码进行 CAS 系统认证;
  4. CAS 认证服务:校验用户信息,并且生成 TGC 放入自己的 Session 中,同时以 Set-Cookie 形式写入 Domain 为 sso.com 的域下,同时生成一个 授权令牌 ST (Service Ticket),然后重定向至系统 A 的地址,重定向的地址中包含生成的 ST;
  5. 系统 A:向 CAS 认证服务发送请求,CAS 认证服务验证票据 (ST) 的有效性。验证成功,表示用户已登录。
  6. 客户端:访问系统 B 用户未登录,重定向至 SSO 认证服务,携带 sso.com 域下的 cookie 值(生成的 TGC);
  7. CAS 认证服务:CAS 认证服务中心发现用户已登录,跳转回系统 B 的地址,并附上票据 (ST) ;
  8. 系统 B:去 CAS 认证服务验证票据 (ST) 的有效性,验证成功即登录成功。

6. OAuth 2.0

OAuth(开放授权)是一个开发标准,允许用户授权 第三方网站 访问他们存储在另外的服务提供商中的信息,而不需要接触到用户名和密码。为了保护数据的安全和隐私,第三方网站访问用户数据前都需要 显式地向用户征求授权。我们常见的 OAuth 认证服务的厂商有微信、QQ、支付宝等。

OAuth 协议又有 1.0 和 2.0 两个版本,2.0 版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。

应用场景有:第三方应用的接入、微服务鉴权互信、接入第三方平台、第一方密码登录等。

授权模式:

  • 授权码模式(Authorization Code Grant)
  • 隐式授权模式(Implicit Grant)
  • 密码模式(Resource Owner Password Credentials Grant)
  • 客户端模式(Client Credentials Grant)

这几种模式都是通过第三方应用授权,生成一个 Token 令牌,然后通过 Token 访问资源。

授权码模式:客户端换取授权码,客户端使用授权码换 token,客户端使用 token 访问资源 隐式授权模式:客户端直接获取 token,不需要换取授权码 密码模式:客户端使用用户名和密码换取 token,客户端使用 token 访问资源 客户端模式:客户端使用客户端信息换取 token,客户端使用 token 访问资源

7. 联合登录

联合登录指同时包含多种凭证校验的登录服务,同时,也可以理解为使用第三方凭证进行校验的登录服务。这个概念有点像 OAuth2.0 的认证方式。

最经典的莫过于 APP 内嵌 H5 的使用场景,当用户从 APP 进入内嵌的 H5 时,我们希望 APP 内已登录的用户能够访问到 H5 内受限的资源,而未登录的用户则需要登录后访问。

这里思路主要有两种,一种是原生跳转内嵌 H5 页面时,将登录态 Token 附加在 URL 参数上,另一种则是内嵌 H5 主动通过与原生客户端制定的协议获取应用内的登录状态。

8. 扫码登录

扫码登录通常见于移动端 APP 中,很多 PC 端的网站都提供了扫码登录的功能,无需在网页上输入任何账号和密码,只需要让移动端 APP (如微信、淘宝、QQ 等等) 中已登录用户主动扫描 二维码 ,再确认登录,以使 PC 端的同款应用得以快速登录的方式就是扫码登录

待扫码阶段:

  1. PC 端:

    打开某个网站 (如 taobao.com) 或者某个 APP (如微信) 的扫码登录入口;就会携带 PC 端的设备信息向服务端发送一个获取二维码的请求;

  2. 服务端:

    服务器收到请求后,随机生成一个 UUID 作为二维码 ID,并将 UUID 与 PC 端的设备信息 关联起来存储在 Redis 服务器中,然后返回给 PC 端;同时设置一个过期时间,在过期后,用户登录二维码需要进行刷新重新获取。

  3. PC 端:

    收到二维码 ID 之后,将二维码 ID 以 二维码的形式 展示,等待移动端扫码。并且此时的 PC 端开始轮询查询二维码状态,直到登录成功。如果移动端未扫描,那么一段时间后二维码会自动失效。

已扫码待确认阶段:

  1. 手机端:

    打开手机端对应已登录的 APP (微信或淘宝等),开始扫描识别 PC 端展示的二维码; 移动端扫描二维码后,会自动获取到二维码 ID,并将移动端登录的信息凭证(Token)和二维码 ID 作为参数发送给服务端,此时手机必须是已登录(使用扫描登录的前提是移动端的应用为已登录状态,这样才可以共享登录态)。

  2. 服务端:

    收到手机端发来的请求后,会将 Token 与二维码 ID 关联,为什么需要关联呢?因为,当我们在使用微信时,移动端退出时,PC 端也应该随之退出登录,这个关联就起到这个作用。然后会生成一个临时 Token,这个 Token 会返回给移动端,一次性 Token 用作确认时的凭证。

已确认阶段:

  1. 手机端:

    收到确认信息后,点击确认按钮,移动端携带上一步中获取的 临时 Token 发送给服务端校验;

  2. 服务端:

    服务端校验完成后,会更新二维码状态,并且给 PC 端生成一个 正式的 Token,后续 PC 端就是持有这个 Token 访问服务端。

  3. PC 端:

    轮询到二维码状态为已登录状态,并且会获取到了生成的 Token,完成登录,后续访问都基于 Token 完成。

9. 一键登录

随着无线互联的发展以及手机卡实名制的推广,手机号俨然已成为特别的身份证明,只要获取到当前手机的手机号并与输入的手机号对比匹配后便能达到校验的功能。

一键登录步骤详解:

  1. SDK 初始化:调用 SDK 方法,传入平台配置的 AppKey 和 AppSecret
  2. 唤起授权页:调用 SDK 唤起授权接口,SDK 会先向运营商发起获取手机号掩码的请求,请求成功后跳到授权页。授权页会显示手机号掩码以及运营商协议给用户确认。
  3. 同意授权并登录:用户同意相关协议,点击授权页面的登录按钮,SDK 会请求本次取号的 Token,请求成功后将 Token 返回给客户端。
  4. 取号:将获取到的 Token 发送到自己的服务器,由服务端携带 Token 调用运营商一键登录的接口,调用成功就返回手机号码。服务端用手机号进行登录或注册操作,返回操作结果给客户端,完成一键登录。