gateway网关获取分布式session的解决方法

首先我们需要解决spring-session-data-redis的序列化问题,spring-session-data-redis默认使用的是java对象序列化,需要Java对象实现Serializable而且在gateway中取出是乱码的. 所以我们要配置session配置类(类是配置在用户模块不是网关模块)

 @Configuration
 public class SessionConfig {
 ​
  @Bean
  public CookieSerializer cookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    return serializer;
  }
 ​
  @Bean
  public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
    return new GenericJackson2JsonRedisSerializer();
  }
 ​
 }


gateway中也要记得引入依赖(spring-session-data-redis貌似可以不引入)

      <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.session</groupId>
             <artifactId>spring-session-data-redis</artifactId>
         </dependency>


在用户模块我们操作分布式session都是通过HttpServletRequest直接存取即可但在gateway中我们无法使用HttpServletRequest所以我们只能直接从redis中取首先我们要获取sessionid

 String cookieValue = exchange.getRequest().getCookies().getFirst(WEB_SESSION_KEY).getValue();

这里有一个坑,cookies中存的sessionid和reids中的格式不同要把sessionid转为base64

 String sessionId = new String(Base64.getDecoder().decode(cookieValue));

现在就可以取出redis中的session了我我用RedisTemplate出现了报错使用这里使用了stringRedisTemplate,最后反序列化redis取出的值

 String sessionKey =REDIS_SESSION_KEY + sessionId;
 // sessionAttr:userLoginState是我这里的写法 具体值取决于你存入的值的名称规则就是sessionAttr:[request.getSession().setAttribute()时指定的名称字段]
 String session =(String)stringRedisTemplate.opsForHash().get(sessionKey,"sessionAttr:userLoginState");
 Gson gson = new Gson();
 User user = gson.fromJson(session, User.class);

gateway完整代码如下:

import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.seig.teabackend.common.model.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
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 reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Base64;

@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
private static final String WEB_SESSION_KEY = "SESSION";
private static final String REDIS_SESSION_KEY = "spring:session:sessions:";
@Resource
private StringRedisTemplate stringRedisTemplate;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
ServerHttpRequest request = exchange.getRequest();
// 1. 请求日志
String requestPath = request.getPath().value();
requestPath = requestPath.replaceFirst("/api/core", "");
String method = request.getMethod().toString().toLowerCase();
log.info("请求唯一标识:" + request.getId());
log.info("请求路径:" + requestPath);
log.info("请求方法:" + method);
log.info("请求参数:" + request.getQueryParams());
String sourceAddress = request.getLocalAddress().getHostString();
log.info("请求来源地址:" + sourceAddress);

// 获取 Session
User user = getSession(exchange);
// gson.fromJson()
log.info(String.valueOf(user));
return chain.filter(exchange);
}

private User getSession(ServerWebExchange exchange) {
String cookieValue = exchange.getRequest().getCookies().getFirst(WEB_SESSION_KEY).getValue();
String sessionId = new String(Base64.getDecoder().decode(cookieValue));

String sessionKey = REDIS_SESSION_KEY + sessionId;

String session = (String) stringRedisTemplate.opsForHash().get(sessionKey, "sessionAttr:userLoginState");
Gson gson = new Gson();
return gson.fromJson(session, User.class);
}


@Override
public int getOrder() {
return 0;
}
}


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
飞龙骑脸
下载 APP