一、思路分析
1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误
二、代码实现
1.系统微服务签发token
(1)在changgou_service_system中创建类: JwtUtil
/*** JWT工具类*/
public classJwtUtil {//有效期为
public static final Long JWT_TTL = 3600000L;//60 * 60 *1000 一个小时//设置秘钥明文
public static final String JWT_KEY = "itcast";/*** 创建token
*@paramid
*@paramsubject
*@paramttlMillis
*@return
*/
public staticString createJWT(String id, String subject, Long ttlMillis) {
SignatureAlgorithm signatureAlgorithm=SignatureAlgorithm.HS256;long nowMillis =System.currentTimeMillis();
Date now= newDate(nowMillis);if(ttlMillis==null){
ttlMillis=JwtUtil.JWT_TTL;
}long expMillis = nowMillis +ttlMillis;
Date expDate= newDate(expMillis);
SecretKey secretKey=generalKey();
JwtBuilder builder=Jwts.builder()
.setId(id)//唯一的ID
.setSubject(subject) //主题 可以是JSON数据
.setIssuer("admin") //签发者
.setIssuedAt(now) //签发时间
.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
.setExpiration(expDate);//设置过期时间
returnbuilder.compact();
}/*** 生成加密后的秘钥 secretKey
*@return
*/
public staticSecretKey generalKey() {byte[] encodedKey =Base64.getDecoder().decode(JwtUtil.JWT_KEY);
SecretKey key= new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");returnkey;
}
}
(2)修改AdminController的login方法, 用户登录成功 则 签发TOKEN
/*** 登录
*@paramadmin
*@return
*/@PostMapping("/login")publicResult login(@RequestBody Admin admin){boolean login =adminService.login(admin);if(login){ //如果验证成功
Map info = new HashMap<>();
info.put("username",admin.getLoginName());
String token= JwtUtil.createJWT(UUID.randomUUID().toString(), admin.getLoginName(), null);
info.put("token",token);return new Result(true, StatusCode.OK,"登录成功",info);
}else{return new Result(false,StatusCode.LOGINERROR,"用户名或密码错误");
}
}
使用postman 测试
2.网关过滤器验证token
(1)在changgou_gateway_system网关系统添加依赖
io.jsonwebtoken
jjwt
0.9.0
(2)创建JWTUtil类
/*** jwt校验工具类*/
public classJwtUtil {//有效期为
public static final Long JWT_TTL = 3600000L;//60 * 60 *1000 一个小时//设置秘钥明文
public static final String JWT_KEY = "itcast";/*** 生成加密后的秘钥 secretKey
*
*@return
*/
public staticSecretKey generalKey() {byte[] encodedKey =Base64.getDecoder().decode(JwtUtil.JWT_KEY);
SecretKey key= new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");returnkey;
}/*** 解析
*
*@paramjwt
*@return*@throwsException*/
public static Claims parseJWT(String jwt) throwsException {
SecretKey secretKey=generalKey();returnJwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
}
(3)创建过滤器,用于token验证
/*** 鉴权过滤器 验证token*/@Componentpublic class AuthorizeFilter implementsGlobalFilter, Ordered {private static final String AUTHORIZE_TOKEN = "token";
@Overridepublic Monofilter(ServerWebExchange exchange, GatewayFilterChain chain) {//1. 获取请求
ServerHttpRequest request =exchange.getRequest();//2. 则获取响应
ServerHttpResponse response =exchange.getResponse();//3. 如果是登录请求则放行
if (request.getURI().getPath().contains("/admin/login")) {returnchain.filter(exchange);
}//4. 获取请求头
HttpHeaders headers =request.getHeaders();//5. 请求头中获取令牌
String token =headers.getFirst(AUTHORIZE_TOKEN);//6. 判断请求头中是否有令牌
if(StringUtils.isEmpty(token)) {//7. 响应中放入返回的状态吗, 没有权限访问
response.setStatusCode(HttpStatus.UNAUTHORIZED);//8. 返回
returnresponse.setComplete();
}//9. 如果请求头中有令牌则解析令牌
try{
JwtUtil.parseJWT(token);
}catch(Exception e) {
e.printStackTrace();//10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现
response.setStatusCode(HttpStatus.UNAUTHORIZED);//11. 返回
returnresponse.setComplete();
}//12. 放行
returnchain.filter(exchange);
}
@Overridepublic intgetOrder() {return 0;
}
}
(4)测试:
注意: 数据库中管理员账户为 : admin , 密码为 : 123456
如果不携带token直接访问,则返回401错误
如果携带正确的token,则返回查询结果