|
@@ -1,139 +0,0 @@
|
|
|
-package com.caimei365.cloud.token;
|
|
|
-
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.apache.commons.lang.StringUtils;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.core.io.buffer.DataBuffer;
|
|
|
-import org.springframework.http.HttpHeaders;
|
|
|
-import org.springframework.http.HttpStatus;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-import org.springframework.web.server.ServerWebExchange;
|
|
|
-import org.springframework.web.server.WebFilter;
|
|
|
-import org.springframework.web.server.WebFilterChain;
|
|
|
-import reactor.core.publisher.Flux;
|
|
|
-import reactor.core.publisher.Mono;
|
|
|
-
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.Arrays;
|
|
|
-
|
|
|
-/**
|
|
|
- * JWT Token
|
|
|
- * <p>
|
|
|
- * 续签逻辑:
|
|
|
- * 登录成功后,用户在未过期时间内继续操作,续签token。
|
|
|
- * 登录成功后,空闲超过过期时间,返回token已失效,重新登录。
|
|
|
- * 实现逻辑:
|
|
|
- * 1.登录成功后将token存储到redis里面(这时候k、v值一样都为token),并设置过期时间为token过期时间
|
|
|
- * 2.当用户请求时token值还未过期,则重新设置redis里token的过期时间。
|
|
|
- * 3.当用户请求时token值已过期,但redis中还在,则JWT重新生成token并覆盖v值(这时候k、v值不一样了),然后设置redis过期时间。
|
|
|
- * 4.当用户请求时token值已过期,并且redis中也不存在,则用户空闲超时,返回token已失效,重新登录。
|
|
|
- *
|
|
|
- * @author : Charles
|
|
|
- * @date : 2021/3/30
|
|
|
- */
|
|
|
-@Slf4j
|
|
|
-@Component
|
|
|
-public class TokenFilter implements WebFilter {
|
|
|
-
|
|
|
- private static final String AUTH = "X-Token";
|
|
|
- /**
|
|
|
- * 需要权限认证的接口路径
|
|
|
- */
|
|
|
- private static final String[] PERMISSION_URLS = new String[]{
|
|
|
- "/user/club/info/update",
|
|
|
- "/user/shop/info/update",
|
|
|
- "/commodity/shop/product/release",
|
|
|
- "/commodity/shop/product/offline",
|
|
|
- "/order/club/cart/add",
|
|
|
- "/order/club/cart/update",
|
|
|
- "/order/club/cart/delete",
|
|
|
- "/order/seller/cart/add",
|
|
|
- "/order/seller/cart/update",
|
|
|
- "/order/seller/cart/delete",
|
|
|
- "/order/club/confirm",
|
|
|
- "/order/club/cancel",
|
|
|
- "/order/club/delete",
|
|
|
- "/order/club/receive",
|
|
|
- "/order/club/second/payment/confirm",
|
|
|
- "/order/submit/generate",
|
|
|
- "/order/submit/recharge",
|
|
|
- "/order/pay/balance/deduction"
|
|
|
- };
|
|
|
-
|
|
|
- private RedisService redisService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- public void setRedisService(RedisService redisService) {
|
|
|
- this.redisService = redisService;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
|
|
- ServerHttpRequest request = exchange.getRequest();
|
|
|
- ServerHttpResponse response = exchange.getResponse();
|
|
|
-
|
|
|
- HttpHeaders header = request.getHeaders();
|
|
|
- String token = header.getFirst(AUTH);
|
|
|
- String url = request.getURI().getPath();
|
|
|
-
|
|
|
- if (StringUtils.isBlank(token) && Arrays.asList(PERMISSION_URLS).contains(url)) {
|
|
|
- log.error("未经授权,Token为空!");
|
|
|
- return tokenErrorResponse(response, "未经授权,Token为空!");
|
|
|
- }
|
|
|
-
|
|
|
- if (StringUtils.isNotBlank(token)) {
|
|
|
- String cacheToken = (String) redisService.get(token);
|
|
|
- // token续签
|
|
|
- if (StringUtils.isNotBlank(cacheToken) && !"null".equals(cacheToken) && JwtUtil.isVerify(cacheToken)) {
|
|
|
- int userId = JwtUtil.parseTokenUid(cacheToken);
|
|
|
- log.debug("Token续签,UserId:" + userId + ",Token:" + token);
|
|
|
- // 再次校验token有效性
|
|
|
- if (!JwtUtil.isVerify(cacheToken)) {
|
|
|
- // 生成token
|
|
|
- String newToken = JwtUtil.createToken(userId);
|
|
|
- // 将token存入redis,并设置超时时间(秒)
|
|
|
- redisService.set(token, newToken, JwtUtil.getExpireTime());
|
|
|
- } else {
|
|
|
- // 重新设置超时时间(秒)
|
|
|
- redisService.expire(token, JwtUtil.getExpireTime());
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 需要验证的路径
|
|
|
- if (Arrays.asList(PERMISSION_URLS).contains(url)) {
|
|
|
- // Token失效
|
|
|
- log.error("Token失效,token:" + token + ",cacheToken:" + cacheToken);
|
|
|
- return tokenErrorResponse(response, "Token失效,请重新登录!");
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- // //TODO 将用户信息存放在请求header中传递给下游业务
|
|
|
- // ServerHttpRequest.Builder mutate = request.mutate();
|
|
|
- // mutate.header("demo-user-name", username);
|
|
|
- // ServerHttpRequest buildReuqest = mutate.build();
|
|
|
- //
|
|
|
- // //todo 如果响应中需要放数据,也可以放在response的header中
|
|
|
- // response.setStatusCode(HttpStatus.OK);
|
|
|
- // response.getHeaders().add("demo-user-name",username);
|
|
|
- // return chain.filter(exchange.mutate()
|
|
|
- // .request(buildReuqest)
|
|
|
- // .response(response)
|
|
|
- // .build());
|
|
|
- return chain.filter(exchange);
|
|
|
- }
|
|
|
-
|
|
|
- private Mono<Void> tokenErrorResponse(ServerHttpResponse response, String responseMsg) {
|
|
|
- response.setStatusCode(HttpStatus.OK);
|
|
|
- response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
|
|
- JSONObject res = new JSONObject();
|
|
|
- res.put("code", -99);
|
|
|
- res.put("msg", responseMsg);
|
|
|
- byte[] responseByte = res.toJSONString().getBytes(StandardCharsets.UTF_8);
|
|
|
- DataBuffer buffer = response.bufferFactory().wrap(responseByte);
|
|
|
- return response.writeWith(Flux.just(buffer));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-}
|