思路: 全局过滤器对所有的请求拦截(生成token有效期30分钟,放入redis设置有效期3天。3天之类可以通过刷新接口自动刷新,超过3天需要重新登录。)

前端在调用接口之前先判断token是否过期(3o分钟),过期则先调刷新接口,换取新token,

1- 引入相关jar

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>

2- 编写Jwt工具类(生成token + 解析token)


package spring.cloud.gateway.common;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.util.StringUtils;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; public class JwtUtil {
public static final String SECRET = "qazwsx123444$#%#()*&& asdaswwi1235 ?;!@#kmmmpom in***xx**&";
public static final String TOKEN_PREFIX = "Bearer";
public static final String LOGIN_URL = "/token/userId/pwd";
public static final String LOGOUT_URL = "/token/userId";
public static final String HEADER_AUTH = "authorization";
public static final String HEADER_USERID = "userid";
//token超时时间
public static final int TOKEN_EXPIRATION_MINUTE = 30;
//token的redis超时时间
public static final int TOKEN_REDIS_EXPIRATION_DAY = 7; public static String generateToken(String userId) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, TOKEN_EXPIRATION_MINUTE); //得到前一天
Date date = calendar.getTime();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.format(date);
//todo 优化token的生层规则
HashMap<String, Object> map = new HashMap<>();
map.put(HEADER_USERID, userId);
String jwt = Jwts.builder()
.setSubject(HEADER_USERID).setClaims(map)
.setExpiration(date)
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
return TOKEN_PREFIX + " " + jwt;
} public static Map<String, String> validateToken(String token) {
HashMap<String, String> tokenMap = new HashMap<String, String>();
if (StringUtils.isEmpty(token)) {
return tokenMap;
}
try {
Map<String, Object> tokenBody = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody();
String userId = String.valueOf(tokenBody.get(HEADER_USERID));
tokenMap.put(HEADER_USERID, userId);
}catch (ExpiredJwtException e){
e.printStackTrace();
}
return tokenMap;
} /**
* 移到jwtUtil中去
*
* @param token
* @return
*/
public static Map<String, String> validateTokenAndUser(String token, String userIdIn) {
Map<String, String> tokenResultMap = new HashMap<>();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) {
return tokenResultMap;
}
tokenResultMap = validateToken(token);
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) {
return tokenResultMap;
}
//判断传入的userid和token是否匹配
String userIdOri = tokenResultMap.get(HEADER_USERID);
if (!userIdIn.equals(userIdOri)) {
return new HashMap<String,String>();
}
return tokenResultMap;
} }


3- 编写过滤器类

package spring.cloud.gateway.filter;

import java.net.URI;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import spring.cloud.gateway.common.JwtUtil;
import spring.cloud.gateway.exception.PermissionException; /**
* 参数参考 https://blog.csdn.net/tianyaleixiaowu/article/details/83375246
* response参考 https://bbs.csdn.net/topics/392412604?list=11074255
*/
@Component
public class AuthFilter implements GlobalFilter { @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders header = request.getHeaders();
HttpMethod method = request.getMethod();
String token = header.getFirst(JwtUtil.HEADER_AUTH);
String userId = header.getFirst(JwtUtil.HEADER_USERID);
PathContainer pathContainer = request.getPath().pathWithinApplication();
String path = pathContainer.value(); //2- 处理登录请求
if (StringUtils.isBlank(token)) {
//是登录接口则放行,否则返回异常
if (path.contains(JwtUtil.LOGIN_URL) && HttpMethod.POST.equals(method)) {
throw new PermissionException("please login");
}
return chain.filter(exchange);
} //3- 处理刷新token请求
if (path.indexOf("refresh") >= 0) {
//放行去掉刷新接口(在刷新前校验userId和token是否匹配)
return chain.filter(exchange);
} //4- 处理刷新token请求
if (path.contains(JwtUtil.LOGOUT_URL) && HttpMethod.DELETE.equals(method)) {
//放行去掉登出接口(在刷新前校验userId和token是否匹配)
return chain.filter(exchange);
} //5- 携带token请求其他业务接口
Map<String, String> validateResultMap = JwtUtil.validateTokenAndUser(token, userId);
if (validateResultMap == null || validateResultMap.isEmpty()) {
throw new PermissionException("token 已经失效");
}
// TODO 将用户信息存放在请求header中传递给下游业务
Route gatewayUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
URI uri = gatewayUrl.getUri();
//表示下游请求对应的服务名如 SPRING-CLOUD-SERVICE SPRING-CLOUD-GATEWAY
String serviceName = uri.getHost(); ServerHttpRequest.Builder mutate = request.mutate();
mutate.header("x-user-id", validateResultMap.get("userid"));
mutate.header("x-user-name", validateResultMap.get("user"));
mutate.header("x-user-serviceName", serviceName);
ServerHttpRequest buildReuqest = mutate.build(); //todo 如果响应中需要放数据,也可以放在response的header中
//ServerHttpResponse response = exchange.getResponse();
//response.getHeaders().add("new_token","token_value");
return chain.filter(exchange.mutate().request(buildReuqest).build());
} }

4- 编写相关接口API

package spring.cloud.gateway.controller;

import org.springframework.web.bind.annotation.*;
import spring.cloud.gateway.common.JwtUtil; import java.util.Map; @RestController
@RequestMapping("/token")
public class TokenController { /**
* 登录接口
* @param user(userID +pwd)
* @return
*/
@PostMapping("/userId/pwd")
public String getToken(@RequestBody Map<String,String> user) {
//用户名密码需要加密处理
String result = "";
if (user == null || user.isEmpty()) {
return result;
}
String userId = user.get("userId");
String pwd = user.get("pwd");
if (!doLogin(userId,pwd)) {
return result;
}
String token = JwtUtil.generateToken(userId);
// todo 将token放入redis中,设置超时时间为 2 * t
return token;
} private Boolean doLogin(String userId,String pwd) {
//后续对接user表验证
if ("admin".equals(userId) && "123".equals(pwd)) {
return true;
}
if ("spring".equals(userId) && "123".equals(pwd)) {
return true;
}
if ("gateway".equals(userId) && "123".equals(pwd)) {
return true;
}
return false;
} /**
* 登出接口
*/ /**
* 刷新token的接口
* 在刷新前校验userId和token是否匹配
*/ }

gateway + jwt 网关认证的更多相关文章

  1. Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作

    Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作 一.背景 二.需求 三.前置条件 四.项目结构 五.网关层代码的编写 1.引入jar包 2.自定义授权管理器 ...

  2. Spring Cloud Gateway 服务网关快速上手

    Spring Cloud Gateway 服务网关 API 主流网关有NGINX.ZUUL.Spring Cloud Gateway.Linkerd等:Spring Cloud Gateway构建于 ...

  3. ASP.NET Core 基于JWT的认证(二)

    ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...

  4. ASP.NET Core 基于JWT的认证(一)

    ASP.NET Core 基于JWT的认证(一) Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计 ...

  5. SpringCloud初体验:四、API GateWay 服务网关

    网关服务很多,比如:Zuul.Kong.spring cloud gateway ……, 这里不纠结哪种性能好,本次体验是用的 spring cloud gateway 更多网关比较可以了解这篇文章: ...

  6. spring cloud 2.x版本 Gateway路由网关教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka ...

  7. ASP.NET Core系列:JWT身份认证

    1. JWT概述 JSON Web Token(JWT)是目前流行的跨域身份验证解决方案. JWT的官网地址:https://jwt.io JWT的实现方式是将用户信息存储在客户端,服务端不进行保存. ...

  8. 【技术博客】JWT的认证机制Django项目中应用

    开发组在开发过程中,都不可避免地遇到了一些困难或问题,但都最终想出办法克服了.我们认为这样的经验是有必要记录下来的,因此就有了[技术博客]. JWT的认证机制Django项目中应用 这篇技术博客基于软 ...

  9. JWT 身份认证优缺点分析以及常见问题解决方案

    本文转载自:JWT 身份认证优缺点分析以及常见问题解决方案 Token 认证的优势 相比于 Session 认证的方式来说,使用 token 进行身份认证主要有下面三个优势: 1.无状态 token ...

随机推荐

  1. 关于Unity中物体分别在本地和世界坐标系对应方向的移动

    方向 Vector3可以定义以世界坐标轴为参考的三维矢量,Vector3.forward,Vector3.up,Vector3.right方别对应物体世界坐标系的Z,Y,X轴方向的单位向量,或者叫三维 ...

  2. vlc-ts

    https://github.com/jiayayao/vlc_2.1.0-vs_2010 https://wenku.baidu.com/view/a0634d26336c1eb91a375d70. ...

  3. 让windows 2003启动后直接进入桌面

    windows 2003启动后进入桌面需要解决的几个问题 1.如何去除掉 ctrl+alt+del的提示界面 2.如何设置自动登录的用户名密码 3.在异常启动时会出现关闭事件跟踪程序 也会导致不能直接 ...

  4. ubuntu更改镜像源

    参考 https://blog.csdn.net/weixin_41762173/article/details/79480832 建议使用ustc.edu的源,其他例如清华的,阿里的连sublime ...

  5. osg shader 相机观察矩阵逆矩阵 求顶点世界坐标

    uniform mat4 osg_ViewMatrixInverse;//osg内置uniform void main() { vec4 posWorld = osg_ViewMatrixInvers ...

  6. eclipse.ini 修改默认编码为 UTF-8

    eclipse.ini 修改默认编码为 UTF-8 打开您的eclipse安装目录,找到eclipse.ini文件 打开eclipse.ini文件,在最下面加入一行代码:-Dfile.encoding ...

  7. monit官方摘录

    Here are the legal global keywords: Keyword Function ----------------------------------------------- ...

  8. 剑指offer——python【第15题】反转链表

    题目描述 翻转一个链表 样例:给出一个链表1->2->3->null,这个翻转后的链表为3->2->1->null 思路 一种比较简单的方法是用“摘除法”.就是先新 ...

  9. Oracle课程档案,第三天

    count(*):有多少行,对行做统计 count(x):列.... sum:和 avg:平均值 min:求最小值 max:求最大值 distinct:取出重复的值 count:计数 group by ...

  10. python全栈开发 * 30知识点汇总 * 180713

    30 re模块2一.正则表达式在线测试 在线测试工具 http://tool.chinaz.com/regex/(一).*?的用法: . 是任意字符 * 是取 0 至 无限长度 ? 是非贪婪模式.合在 ...