思路: 全局过滤器对所有的请求拦截(生成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. 对List遍历过程中添加和删除的思考

    对List遍历过程中添加和删除的思考 平时开发过程中,不少开发者都遇到过一个问题:在遍历集合的的过程中,进行add或者remove操作的时候,会出现2类错误,包括:java.util.Concurre ...

  3. 服务器tail输出正常,vim打开中文乱码

    修改服务器端, 在/etc/vim/vimrc文件末尾加上 set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936set termencodi ...

  4. CSS实现自适应九宫格布局 大全

    看到微博和朋友圈都实现了图片九宫格,曾经有次面试也问到了九宫格这个问题,当时想到的是先固定每个单元格的宽高,然后进行浮动.今天想折腾一下,实现自适应父元素宽度的布局.这次我只写了四种方式去实现九宫格, ...

  5. 机器人学 —— 机器人感知(Location)

    终于完成了Robotic SLAM 所有的内容了.说实话,课程的内容比较一般,但是作业还是挺有挑战性的.最后一章的内容是 Location. Location 是 Mapping 的逆过程.在给定ma ...

  6. UCloud 的安全秘钥 (计蒜客初赛第五场)(待解决)

    20.7% 1200ms 262144K 每个 UCloud 用户会构造一个由数字序列组成的秘钥,用于对服务器进行各种操作.作为一家安全可信的云计算平台,秘钥的安全性至关重要.因此,UCloud 每年 ...

  7. LomBok插件的使用

    LomBok插件的使用 By Zhai 简介: LomBok是一个通过简单注解就可以减少一些冗余代码编写的小工具.例如 @Setter @Getter 用于实例类上该类就不需要写set get 方法. ...

  8. Unity 为队伍设置不同颜色的shader

    在魔兽争霸等一些游戏中,我们通过模型的颜色就能很轻松的区分队伍,如下:   实现的方法有很多,比如: 1,为不同队伍各出一张不同颜色的贴图(Hmmm,war3有的地图可以容纳12只队伍,美术大大们会很 ...

  9. HTML、CSS知识点,面试开发都会需要--No.3 盒子模型

    No.3 盒子模型 1.盒子模型属性 (1)包含的CSS属性:width.height.padding.border.margin. 1.盒子模型属性 (1)包含的CSS属性: width.heigh ...

  10. Gym 101981K - Kangaroo Puzzle - [玄学][2018-2019 ACM-ICPC Asia Nanjing Regional Contest Problem K]

    题目链接:http://codeforces.com/gym/101981/problem/K Your friend has made a computer video game called “K ...