思路: 全局过滤器对所有的请求拦截(生成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. Sword 内核队列一

    1.gfifo概述 gfifo是一个First In First Out数据结构,它采用环形循环队列的数据结构来实现:它提供一个无边界的字节流服务,最重要的一点是,它使用并行无锁编程技术,即当它用于只 ...

  2. 设计模式——proxy代理模式

    目录 概述 定义 角色 为什么会有代理模式? 应用场景 示例 静态代理 例子 动态代理 JDK中生成代理对象的API 代码示例: 代码示例2 Cglib代理 代码示例 AOP(AspectOrient ...

  3. java改单个插入为批量插入

    单条insert into table value() 13W数据需要执行7小时 变成inert into table value(),(),(),(),() inert into table val ...

  4. 【QT】QT更改构建目录

    菜单“工具”-“选项”. Qt Creator怎样更改默认构建目录_百度经验 https://jingyan.baidu.com/article/6181c3e0b9d170152ef153af.ht ...

  5. 网络编程 -- RPC实现原理 -- 目录

    -- 啦啦啦 -- 网络编程 -- RPC实现原理 -- NIO单线程 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V1 网络编程 -- RPC实现原理 -- NIO多线程 -- ...

  6. windows pm2 启动nodejs失败:Error: EBADF: bad file descriptor, uv_pipe_open

    windows下打开命令窗口,安装pm2:npm install pm2 -g pm2成功安装,在项目目录下用pm2启动服务:pm2 start index.js,结果启动失败,错误如下: .pm2\ ...

  7. 垃圾wps弹出,现在连关闭按钮都不给了

    垃圾wps弹出,现在连关闭按钮都不给了,有点起色就变得相当垃圾.

  8. 使用npm安装webpack失败时,可能被墙要为cmd命令行设置代理

    一.搜索到的相关概念: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. npm是 Node packaged Modules(node的包管理工具).本身用n ...

  9. [原]Docker-issue(2) http: server gave HTTP response to HTTPS client

    系统环境 查看 文章末尾 附录 问题点:新建local registry后,push新的image到local registry  未能成功,并报错误: The push refers to repo ...

  10. python DBUtils 线程池 连接 Postgresql(多线程公用线程池,DB-API : psycopg2)

    一.DBUtils DBUtils 是一套允许线程化 Python 程序可以安全和有效的访问数据库的模块,DBUtils提供两种外部接口: PersistentDB :提供线程专用的数据库连接,并自动 ...