统一认证
约 3063 字大约 10 分钟
2024-08-08
在项目开发中,存在平台间互相免登的需求。实现互相免登并不难,平台之间互相对接一下对方的免登流程即可,问题是频繁的免登对接是比较耗费资源的,如果有一个第三方的统一认证平台,不同的平台只与统一认证平台对接一次,即可实现所有平台(对接了统一认证的平台)的免登,那就美滋滋了。第三方的统一认证平台也有不少,比如微信、唯ID(随便找的个小体量的统一认证平台)
项目中的运用
统一认证主要流程是比较简单的,系统 A 从统一认证平台拿到统一认证的 token 并交给系统 B,系统 B 拿着统一认证 token 从统一认证平台获取用户信息,之后完成内部的登录逻辑就完事了,整体流程图如下

我们更进一步的梳理下项目中统一认证的主要环节,时序图如下
1、系统
A与系统B需要在统一认证平台绑定好两个渠道之间的关系(暂且称为渠道A、渠道B)2、系统
A请求统一认证平台,带上请求的签名、目标渠道(渠道B)3、系统
A通过url携带统一认证token跳转系统B4、系统
B拿到统一认证token,带上请求的签名、token等参数去请求统一认证平台,获取用户信息,完成系统A到系统B的免登
统一认证
token是有有效期的,而且出于安全考虑,这个token也只能被使用一次

身份认证和用户授权
项目中的统一认证主要流程比较简单,我们再了解一下身份认证和用户授权的内容
SSO(Signle Sign On):单点登录,在多个系统中,用户只需要登录一次,访问其他系统不再需要登录。SSO指的是一类解决方案,实现方式很多,比如JWT+ 网关、CASJWT(JSON Web Token):JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的CAS(Central Authentication Service):中央认证服务,为耶鲁大学发起的一个开源项目,是实现SSO单点登录的框架OAuth2:OAuth 2.0是一个关于授权(authorization)的开放网络标准
JWT
JWT 的组成
JWT 由以下三部分依次排列组成,中间用点 . 隔开
Header(头部)Payload(载荷)Signature(签名)

Header
头部用来描述该 JWT 最基本的信息,例如其类型以及签名所用的算法等
alg:表示签名的算法(algorithm),默认是HMAC SHA256,简写为HS256typ:表示这个令牌(token)的类型(type),JWT令牌统一写为JWT
{
"typ": "JWT",
"alg": "HS256"
}将上面的 JSON 对象使用 Base64 或 Base64URL 算法转成字符串
如果生成的 token 可能放置在 url 上,建议使用 Base64URL,因为 +、/、= 这三个字符在 url 有特殊意义,Base64Url 编码会将 +、/ 替换成 -、_,并且将 = 去掉
Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了 7 个官方字段,供选用
iss (issuer):签发人exp (expiration time):过期时间sub (subject):主题aud (audience):受众nbf (Not Before):生效时间iat (Issued At):签发时间jti (JWT ID):编号
除了选用官方提供的字段,还可以在这个部分定义其他字段,比如:
{
"code": "9527",
"name": "凌凌漆",
"admin": true
}需要注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分,同样的,这个 JSON 对象也要使用 Base64 或 Base64URL 算法转成字符串
Signature
Signature 部分是对前两部分的签名,防止数据篡改
根据指定的密钥(secret),以及 Header 中指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)算出签名以后,把 Header、Payload、Signature 三个部分用 . 连接,拼成一个字符串,就可以了
加密的秘钥只有服务端知道,不能泄露,否则其他人也可以生成 token
JWT 特点
1、
JWT默认是不加密的,但我们可以在生成原始token以后,用密钥再加密一次2、
JWT在不加密的情况下,不能将私密数据写入JWT中3、
JWT不仅可以用于认证,也可以用于交换信息。有效使用JWT,可以降低服务器查询数据库的次数4、
JWT的最大缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑5、
JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证6、为了减少盗用,
JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输
CAS
我们以淘宝(https://www.taobao.com/)、天猫(https://www.tmall.com/)为例。淘宝、天猫的访问域名是不一样的,相当于是两个系统,在淘宝登录之后,再去访问天猫还是需要登录的,因为我们存储的用户 token 这些信息是不能跨域的。我们想要达到在淘宝登录之后,访问天猫无需再次登录的效果,该怎么做呢?接下来,我们来看一看 CAS 是怎么玩的
1、点击淘宝、天猫去登录,都会跳转到同一个页面(后续称为 SSO 登录页面,https://login.taobao.com/),区别在于
url上拼接的重定向地址不一样2、用户访问淘宝购物车,重定向至
SSO登录页面,完成登录后携带用户token信息,重定向到淘宝页面3、用户访问天猫页面点击去登录,重定向至
SSO登录页面,SSO登录页面能获取到用户token信息(表示已登录),直接重定向到天猫页面4、用户不需要在天猫进行登录操作,就已经是登录状态了

OAuth2
在 OAuth 之前,访问权限是通过用户输入用户名、密码的形式进行验证,这种形式是不安全的。OAuth 的出现就是为了解决访问资源的安全性以及灵活性。OAuth 使得第三方应用对资源的访问更加安全
在 OAuth 2.0 的协议交互中,有四个角色的定义:
资源所有者(
Resource Owner):资源服务器上数据的拥有者,比如我是微信用户,那么我就是我微信上个人信息数据的所有者资源服务器(
Resource Server):保存受保护的用户资源服务器,比如微信的服务器客户端(
Client):想要访问用户资源的客户端,比如微信以外的第三方应用、网站授权服务器(
Authorization Server):在获取用户的同意授权后,颁发访问令牌给客户端,以便其获取用户资源
OAuth 思路
OAuth 在“客户端”与“资源服务器”之间,设置了一个授权层。“客户端”不能直接登录“资源服务器”,只能登录授权层,以此将用户与客户端区分开来。“客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期
“客户端”登录授权层以后,“资源服务器”根据令牌的权限范围和有效期,向“客户端”开放用户的资源
客户端的授权模式
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0 定义了四种授权方式:
授权码模式(
authorization code)简化模式(
implicit)密码模式(
resource owner password credentials)客户端模式(
client credentials)
授权码模式
授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与“授权服务器”进行互动,步骤如下:
1、用户访问客户端,客户端将用户导向授权服务器
2、用户选择是否给客户端授权
3、用户给予授权,授权服务器将用户导向客户端指定的地址,同时附上一个授权码
4、客户端收到授权码,向授权服务器申请令牌(客户端的后台服务器完成的操作,用户不可见)
5、授权服务器核对授权码和重定向
URL验证,确认没问题,向客户端发放访问令牌(access token)和更新令牌(refresh token)
上面的流程不理解没关系,我们以 H5 网页获取微信用户头像、昵称为例来说明(起初 H5 网页是可以直接获取微信用户头像、昵称的,在 2022 年的一次改版后,网页上获取是需要用户授权的)

简化模式
简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了“授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。步骤如下:
1、客户端将用户导向认证服务器
2、用户选择是否给客户端授权
3、用户给予授权,授权服务器将用户导向客户端指定的地址,并在
URI的Hash部分包含了访问令牌4、浏览器向资源服务器发送请求,内容不包含上一步收到的
Hash值5、资源服务器返回一个网页,其中包含的代码可以获取
Hash值中的令牌6、浏览器执行上一步获得的脚本,提取出令牌
7、浏览器将令牌发给客户端
密码模式
密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。就好比我们在第三方网站使用 QQ 登录时,直接填写 QQ 的账号和密码
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式
客户端模式
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向“授权服务器”进行认证。严格地说,客户端模式并不属于 OAuth 框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"资源服务器"提供服务,其实不存在授权问题