gateway和jwt网关认证实现过程解析

网友投稿 371 2022-12-22


gateway和jwt网关认证实现过程解析

这篇文章主要介绍了gateway和jwt网关认证实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

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

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

1引入相关jar

org.springframework.cloud

spring-cloud-starter-gateway

io.jsonwebtoken

jjwt

0.9.0

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_USERIDhttp:// = "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 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 validateToken(String token) {

HashMap tokenMap = new HashMap();

if (StringUtils.isEmpty(token)) {

return tokenMap;

}

try {

Map 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 validateTokenAndUser(String token, String userIdIn) {

Map 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();

}

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 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 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 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是否匹配

*/

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring的组合注解和元注解原理与用法详解
下一篇:java中PreparedStatement和Statement详细讲解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~