当前位置:网站首页>API Gateway/API 网关(四) - Kong的使用 - 集成Jwt和熔断插件
API Gateway/API 网关(四) - Kong的使用 - 集成Jwt和熔断插件
2022-04-23 14:11:00 【anron】
一、前言
使用Kong中的JWT插件需要先在Kong的Consumers中创建一个Consumer,然后在该Consumer的Credentials中设置JWT的key和secret。
假定在3个项目组中共用一个单点登录模块的这么一个场景,使用Kong网关来对JWT Token进行拦截。
- A项目组负责单点登录
/api/user 提供登录,登出的接口
- B项目组负责APP1
/api/app1 应用1
/api/common/app1 不需要登录的查询页面
- C项目组负责APP2
/api/app2 应用2
/api/common/app2 不需要登录的查询页面
Kong网关不对/api/user,/api/common进行JWT Token拦截,只对/api/app1,/api/app2进行JWT Token拦截
用户登录时调用/api/user/login接口验证用户名和密码,验证通过后系统将userid和mobile写入到JWT Token中,并以该Token为KEY放入redis中。
用户端登录后把JWT Token放入HTTP Header中,请求/api/app1或者/api/app2的应用接口,如果JWT Token无效或过期,在Kong网关就被拦截了,不会调用到后端的/api/app1或是/api/app2的应用接口。
app1或是app2接收到请求后,先读取出HTTP Header中的Authorization值(即:Bearer + 1个空格+Token),然后读取本项目中的redis,如果没找到数据就调用A项目组的远程接口(各个项目组有自己的DB,不可以互相访问其他项目的DB,只能通过远程接口来进行访问),出于安全性考虑,B和C项目组没有密钥,无法对Token进行解析,只有A项目组才能从Token中解析出UserID和Mobile。
Kong网关中没有找到这样的功能:自动解析Token中的UserID和Mobile,添加到Header后再调用后端的应用,不用后面再去解析。虽然Request Transformer插件可以remove/rename/replace/add/append对应的body/headers/querstring。
二、创建用户
2.1 添加Consumer
点击Consumers中的Create Consumer按钮,然后输入username,username=AllUsers,或者随便取个名称,只创建一个即可。
所有用户共用一个Consumer,即有优点也有缺点。
优点:不需要同步Kong中的Consumer和自己数据库的用户数据
缺点:限流等插件的使用只能按IP,不能按Consumer限制了。
2.2 创建Key和Secret
Credentials->JWT->Create JWT ,algorithm=HS256,其他默认空即可
三、添加JWT插件
设置claims to verify = exp,否则过期的token都可以请求,nbf可以不用设置
exp: 定义jwt的过期时间
nbf: 定义jwt的生效时间
设置了exp后,如果token过期了会提示"token expired"。
四、Java工程
单点登录工程下的部分模块,主要是JWT Token的颁发
4.1 修改POM文件
在pom.xml文件中添加jwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.3.0</version>
</dependency>
4.2 JwtUtil类
JWT_KEY、JWT_SECRET要与Kong中的Customer里面的设置相同
package com.anron.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
/**
* @Author: Anron
* @Date: 2020/4/13 14:07
*/
public class JwtUtil {
private static final String JWT_KEY = "9vQeIbdszK6Pq6Lcf0y8khnQ6yr5779P";
private static final String JWT_SECRET = "sZuEfoA9Vkwm8mhkM6Nr97eDX2YGdSu5";
/**
* 7天过期
*/
public static final long JWT_EXPIRATION = (long) 7 * 24 * 60 * 60000;
/**
* 测试环境30分钟过期
*/
public static final long JWT_EXPIRATION_TEST = (long) 30 * 60000;
/**
* iat 签发日期 withIssuedAt
* nbf 生效时间 withNotBefore
* exp 过期时间 withExpiresAt
* sub 主题
* iss 签发人
* aud 接收方
*/
public static String createJwtToken(Integer userId, String userNameOrMobile, long ttlMillis) {
String token = null;
try {
token = JWT.create()
.withIssuer(JwtUtil.JWT_KEY)
.withIssuedAt(new Date())
.withNotBefore(new Date())
.withClaim("userid", userId)
.withClaim("username", userNameOrMobile)
.withClaim("sub", "anron company")
.withExpiresAt(new Date(System.currentTimeMillis() + ttlMillis))
.sign(Algorithm.HMAC256(JwtUtil.JWT_SECRET));
} catch (JWTCreationException e){
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
return token;
}
public static DecodedJWT decryptToken(final String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(JwtUtil.JWT_SECRET))
.withIssuer(JwtUtil.JWT_KEY)
.build();
jwt = verifier.verify(token);
} catch (TokenExpiredException e) {
e.printStackTrace();
} catch (JWTDecodeException e){
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
return jwt;
}
}
4.3 Test类
package com.anron;
import com.anron.util.JwtUtil;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class AnronApplicationTests {
@Test
void contextLoads() {
Integer userId = 1001;
String userName = "admin";
String token = JwtUtil.createJwtToken(userId, userName, JwtUtil.JWT_EXPIRATION);
System.out.println(token);
}
@Test
void test1() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbnJvbiBjb21wYW55IiwibmJmIjoxNTkwMTI3MTY3LCJpc3MiOiI5dlFlSWJkc3pLNlBxNkxjZjB5OGtoblE2eXI1Nzc5UCIsImV4cCI6MTU5MDczMTk2NywiaWF0IjoxNTkwMTI3MTY3LCJ1c2VyaWQiOjEwMDEsInVzZXJuYW1lIjoiYWRtaW4ifQ.AeoDSUZRPsoQAUfkJUTZJuU5e-CI5SEmihrHlw39Cuc";
DecodedJWT jwt = JwtUtil.decryptToken(token);
if (jwt != null) {
System.out.println("userid = " + jwt.getClaim("userid").asInt());
System.out.println("username = " + jwt.getClaim("username").asString());
System.out.println("sub = " + jwt.getClaim("sub").asString());
System.out.println("签发时间 = " + jwt.getClaim("iat").asDate());
System.out.println("生效时间 = " + jwt.getClaim("nbf").asDate());
System.out.println("过期时间 = " + jwt.getClaim("exp").asDate());
}
}
}
五、熔断插件
在Kong中添加个Request Termination插件,配置用默认即可
版权声明
本文为[anron]所创,转载请带上原文链接,感谢
https://blog.csdn.net/anron/article/details/105736816
边栏推荐
猜你喜欢
教育行业云迁移最佳实践:海云捷迅使用HyperMotion云迁移产品为北京某大学实施渐进式迁移,成功率100%
星界边境Starbound创意工坊订阅的mod的存放路径
ThreadGroup ThreadGroup implémente l'interface threadfactory en utilisant la classe Introduction + Custom thread Factory
RecyclerView进阶使用-实现仿支付宝菜单编辑页面拖拽功能
字节面试编程题:最小的K个数
Logback logger and root
MYSQL一种分表实现方案及InnoDB、MyISAM、MRG_MYISAM等各种引擎应用场景介绍
使用Executors类快速创建线程池
Uni app message push
金融行业云迁移实践 平安金融云整合HyperMotion云迁移解决方案,为金融行业客户提供迁移服务
随机推荐
修改Firebase Emulators的默认侦听IP
OpenStack命令操作
elk安装
线程间控制之CountDownLatch和CyclicBarrier使用介绍
关于云容灾,你需要知道这些
redis数据库讲解(四)主从复制、哨兵、Cluster群集
GFS分布式文件系统(理论)
解决ssh配置文件优化以及连接慢的问题
VMware15Pro在Deepin系统里面挂载真机电脑硬盘
mysql 5.1升级到5.610
x509证书cer格式转pem格式
grep无法重定向到文件的问题
mysql 5.1升级到5.67
微信小程序将原生请求通过es6的promise来进行优化
std::map 和 std::vector 内存释放
Five ways of using synchronized to remove clouds and fog are introduced
处理 mkdir:无法创建目录“aaa“:只读文件系统
什么是云迁移?云迁移的四种模式分别是?
Operation instructions of star boundary text automatic translator
Use the executors class to quickly create a thread pool