gateway + jwt 网关认证

摘要:
io.jsonwebtoken<版本><&publicstaticfinalStringHEADER_AUTH=“授权”;>SECRET).compact();字符串>if(StringUtils.isEmpty(token)){returntokenMap;}try;

思路: 全局过滤器对所有的请求拦截(生成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 网关认证》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇VMware VCSA 6.7基本功能小程序微信支付申请与配置完整版操作流程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Haskell学习笔记

…高阶函数 map :: (a->b) ->[a] ->[b],将函数f依次应用于序列[a],得到新的序列[b]。 filter :: (a->bool)->[a]->[a],利用函数f过滤序列[a]。 这两个函数都可用list comprehension来实现,不过在某些情况下更简洁。利用这两个函数和CF组合可以...

基于C++代码的UE4学习(四)—— 定时器

在UE中有专门的类用来完成定时器的功能,它就是FTimerHandle类。 我们来完成一个例子,每隔一段时间之后,让一个ACTOR自我复制,在一定范围内随机生成。 这是ACTOR的头文件: 1 // Fill out your copyright notice in the Description page of Project Settings. 2...

微信开发-ACCESS TOKEN 过期失效解决方案

微信开发-ACCESS TOKEN 过期失效解决方案 起因:因为access_token的重要性,开发过微信的都知道,但是他有自己的生命周期,官方解释为:"有效期为7200秒",一天调用2000次。流量一高,就over了,没办法,龙哥不帮我们解决问题,我们就要自己解决,不能等死。 解决思路很简单:建立公共access token数据,有效期内不重新创建ac...

写了个用jquery控制select只读(select选项可以供用户查看但不能改变初始选中值)

转载自: http://www.cnblogs.com/case/articles/1864500.html <scripttype="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> &...

Windows访问令牌模拟窃取以及利用(T1134)

Token简介 Windows下有两种类型的Token Delegation token(授权令牌):用于交互会话登录(例如本地用户直接登录、远程桌面登录) Impersonation token(模拟令牌):用于非交互登录(利用net use访问共享文件夹 两种token只在系统重启后清除,具有Delegation token的用户在注销后,该Toke...

iframe用法总结

<p><iframe>是框架的一种形式,也比较常用到。 </p><div class="blogstory"><p><span style="font-size:18px;"><span style="color:#0000ff;"><span style="font...