SpringCloudAlibaba统⼀门户:基于⽹关的统⼀⽤户认证⽅案
本讲咱们涉及以下三⽅⾯内容:
传统的⽤户认证⽅案;
JWT 与 JJWT;
基于⽹关的统⼀⽤户认证。
传统的⽤户认证⽅案
我们直奔主题,什么是⽤户认证呢?对于⼤多数与⽤户相关的操作,软件系统⾸先要确认⽤户的⾝份,因此会提供⼀个⽤户登录功能。⽤户输⼊⽤户名、密码等信息,后台系统对其进⾏校验的操作就是⽤户认证。⽤户认证的形式有多种,最常见的有输⼊⽤户名密码、⼿机验证码、⼈脸识别、指纹识别等,但其⽬的都是为了确认⽤户的⾝份并与之提供服务。
在传统的单体单点应⽤时代,我们会开发⽤户认证的服务类,从登录界⾯提交的⽤户名密码等信息通过⽤户认证类进⾏校验,然后获取该⽤户对象将其保存在 Tomcat 的 Session 中,如下所⽰:
随着系统流量的增⾼,单点应⽤以⽆法⽀撑业务运⾏,应⽤出现⾼延迟、宕机等状况,此时很多公司会将应⽤改为 Nginx 软负载集,通过⽔平扩展提⾼系统的性能,于是应⽤架构就变成了这个样⼦。
虽然改造后系统性能显著提⾼,但你发现了么,因为之前⽤户登录的会话数据都保存在本地,当 Nginx
将请求转发到其他节点后,因为其他节点没有此会话数据,系统就会认为没有登录过,请求的业务就会被拒绝。从使⽤者的⾓度会变成⼀刷新页⾯后,系统就让我重新登录,这个使⽤体验⾮常糟糕。
我们来分析下,这个问题的根本原因在于利⽤ Session 本地保存⽤户数据会让 Java Web 应⽤变成有状态的,在集环境下必须保证每⼀个 Tomcat 节点的会话状态⼀致的才不会出问题。因此基于 Redis 的分布式会话存储⽅案应运⽽⽣,在原有架构后端增加 Redis 服务器,将⽤户会话统⼀转存⾄ Redis 中,因为该会话数据是集中存储的,所以不会出现数据⼀致性的问题。
但是,传统⽅案在互联⽹环境下就会遇到瓶颈,Redis 充当了会话数据源,这也意味着 Redis 承担了所有的外部压⼒,在互联⽹数以亿计的庞⼤⽤户规模下,如果出现突发流量洪峰,Redis 能否经受考验就会成为系统的关键风险,稍有差池系统就会崩溃。
那如何解决呢?其实还有⼀种巧妙的设计,在⽤户认证成功,后⽤户数据不再存储在后端,⽽改为在客户端存储,客户端每⼀次发送请求时附带⽤户数据到 Web 应⽤端,Java 应⽤读取⽤户数据进⾏业务处理,因为⽤户数据分散存储在客户端中,因此并不会对后端产⽣额外的负担,此时认证架构会变成下⾯的情况。
当⽤户认证成功后,在客户端的 Cookie、LocalStorage 会持有当前⽤户数据,在 Tomcat 接收到请求后便可获取⽤户数据进⾏业务处理。但细⼼的你肯定也发现,⽤户的敏感数据是未经过加密的,在存储与传输过程中随时都有泄密的风险,决不能使⽤明⽂,必须要对其进⾏加密。
那如何进⾏加密处理呢?当然,你可以⾃⼰写加解密类,但更通⽤的做法是使⽤ JWT 这种标准的加密⽅案进⾏数据存储与传输。Json Web Token(JWT)介绍
⽆论是微服务架构,还是前后端分离应⽤,在客户端存储并加密数据时有⼀个通⽤的⽅案:Json Web Token(JWT),JWT是⼀个经过加密的,包含⽤户信息的且具有时效性的固定格式字符串。下⾯这是⼀个标准的JWT字符串。
这段加密字符串由三部分组成,中间由点“.”分隔,具体含义如下。
第⼀部分标头(Header):
标头通常由两部分组成:令牌的类型(即 JWT)和所使⽤的签名算法,例如 HMAC SHA256 或 RSA,下⾯是标头的原⽂:
{
"alg": "HS256",
"typ": "JWT"
}
然后,此 JSON 被 Base64 编码以形成 JWT 的第⼀部分。
eyJhbGciOiJIUzI1NiJ9
第⼆部分载荷(Payload):
载荷就是实际的⽤户数据以及其他⾃定义数据。载荷原⽂如下所⽰。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对原⽂进⾏ Base64 编码形成 JWT 的第⼆部分。
eyJzdWIiOiJ7XCJ1c2VySWRcIjoyLFwidXNlcm5hbWVcIjpcImxpc2lcIixcIm5hbWVcIjpcIuadjuWbm1wiLFwiZ3JhZGVcIjpcInZpcFwifSJ9
第三部分签名(Sign):
签名就是通过前⾯两部分标头+载荷+私钥再配合指定的算法,⽣成⽤于校验 JWT 是否有效的特殊字符串,签名的⽣成规则如下。HMACSHA256(base64UrlEncode(header) + "." +  base64UrlEncode(payload),  secret)
⽣成的签名字符串为:
NT8QBdoK4S-PbnhS0msJAqL0FG2aruvlsBSyG226HiU
将以上三部分通过“.”连接在⼀起,就是 JWT 的标准格式了。
JWT 的创建与校验
JJWT 的使⽤是⾮常简单的,下⾯我们⽤代码进⾏说明,关键代码我已做好注释。
第⼀步,l 引⼊ JJWT 的 Maven 依赖。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
第⼆步,编写创建 JWT 的测试⽤例,模拟真实环境 UserID 为 123 号的⽤户登录后的 JWT ⽣成过程。
@SpringBootTest
public class JwtTestor {
/**
* 创建Token
*/
@Test
public void createJwt(){
//私钥字符串
String key = "1234567890_1234567890_1234567890";
//1.对秘钥做BASE64编码
String base64 = new BASE64Encoder().Bytes());
//2.⽣成秘钥对象,会根据base64长度⾃动选择相应的 HMAC 算法
SecretKey secretKey = Keys.Bytes());
//3.利⽤JJWT⽣成Token
String data = "{\"userId\":123}"; //载荷数据
String jwt = Jwts.builder().setSubject(data).signWith(secretKey)pact();
System.out.println(jwt);
}
}
运⾏结果产⽣ JWT 字符串如下:
第三步,验签代码,从 JWT 中提取 123 号⽤户数据。这⾥要保证 JWT 字符串、key 私钥与⽣成时保持⼀致。否则就会抛出验签失败JwtException。
/**
* 校验及提取JWT数据
*/
@Test
public void checkJwt(){
String jwt = "JzdWIiOiJ7XCJ1c2VySWRcIjoxMjN9In0.1p_VTN46sukRJTYFxUg93CmfR3nJZRBm99ZK0e3d9Hw";
//私钥
String key = "1234567890_1234567890_1234567890";
//1.对秘钥做BASE64编码
String base64 = new BASE64Encoder().Bytes());
//2.⽣成秘钥对象,会根据base64长度⾃动选择相应的 HMAC 算法
SecretKey secretKey = Keys.Bytes());
//3.验证Token
try {
spring aop应用场景//⽣成JWT解析器
JwtParser parser = Jwts.parserBuilder().setSigningKey(secretKey).build();
//解析JWT
Jws<Claims> claimsJws = parser.parseClaimsJws(jwt);
//得到载荷中的⽤户数据
String subject = Body().getSubject();
System.out.println(subject);
}catch (JwtException e){
//所有关于Jwt校验的异常都继承⾃JwtException
System.out.println("Jwt校验失败");
e.printStackTrace();
}
}
运⾏结果如下:
{"userId":123}
以上便是 JWT 的⽣成与校验代码,你会发现在加解密过程中,服务器私钥 key 是保障 JWT 安全的命脉。对于这个私钥在⽣产环境它不能写死在代码中,⽽是加密后保存在 Nacos 配置中⼼统⼀存储,同时定期更换私钥以防⽌关键信息泄露。
讲到这应该你已掌握 JWT 的基本⽤法,但是在微服务架构下⼜该如何设计⽤户认证体系呢?
基于⽹关的统⼀⽤户认证
下⾯我们结合场景讲解 JWT 在微服务架构下的认证过程。这⾥我将介绍两种⽅案:
服务端⾃主验签⽅案;
API ⽹关统⼀验签⽅案。
服务端⾃主验签⽅案
⾸先咱们来看服务端验签的架构图。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。