统一认证
3063字约10分钟
2024-08-08
在项目开发中,存在平台间互相免登的需求。实现互相免登并不难,平台之间互相对接一下对方的免登流程即可,问题是频繁的免登对接是比较耗费资源的,如果有一个第三方的统一认证平台,不同的平台只与统一认证平台对接一次,即可实现所有平台(对接了统一认证的平台)的免登,那就美滋滋了。第三方的统一认证平台也有不少,比如微信、唯ID(随便找的个小体量的统一认证平台)
项目中的运用
统一认证主要流程是比较简单的,系统 A
从统一认证平台拿到统一认证的 token
并交给系统 B
,系统 B
拿着统一认证 token
从统一认证平台获取用户信息,之后完成内部的登录逻辑就完事了,整体流程图如下
我们更进一步的梳理下项目中统一认证的主要环节,时序图如下
1、系统
A
与系统B
需要在统一认证平台绑定好两个渠道之间的关系(暂且称为渠道A
、渠道B
)2、系统
A
请求统一认证平台,带上请求的签名、目标渠道(渠道B
)3、系统
A
通过url
携带统一认证token
跳转系统B
4、系统
B
拿到统一认证token
,带上请求的签名、token
等参数去请求统一认证平台,获取用户信息,完成系统A
到系统B
的免登
统一认证
token
是有有效期的,而且出于安全考虑,这个token
也只能被使用一次
身份认证和用户授权
项目中的统一认证主要流程比较简单,我们再了解一下身份认证和用户授权的内容
SSO(Signle Sign On)
:单点登录,在多个系统中,用户只需要登录一次,访问其他系统不再需要登录。SSO
指的是一类解决方案,实现方式很多,比如JWT
+ 网关、CAS
JWT(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
,简写为HS256
typ
:表示这个令牌(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
框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"资源服务器"提供服务,其实不存在授权问题