springboot利用springsession实现redis共享session,并且自定义sessionid
来源:互联网 发布:漫画控不能连接网络 编辑:程序博客网 时间:2024/06/01 07:55
一、初衷
作为一个刚入行的小白,在公司接手了一个springboot的项目,项目中我们完全使用session,管理用户的登陆信息及权限,项目完成时,我们需要集成某公司的nigix服务器,甲方要求,并且由甲方提供,一开始,我们接入之后,发现session丢失,就是nigix每次转发过来的请求其中cookie都会丢失,这个问题我们折腾了好多天,没有解决,后来发现他们的nigix服务器就是不能带cookie过来,因为集成了统一身份认证,没次请求都会带一个固定的请求头,并且请求头里面的数据会最为用户的id,所以考虑以下,决定用springsession来管理HTTPsession,保存到redis服务器中,实现session共享,并且用用户的id来做为中间件,在redis中管理session,从而间接的实现自定义sessionid。
二、干货
1.引用依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 在配置文件application.properties中加入参数
# database namespring.redis.database=0# server host1spring.redis.host=********** //redis服务器ip# server password#spring.redis.password= //redis服务器密码 默认是没有的#connection portspring.redis.port=6379 //redis服务器端口号# pool settings ...spring.redis.pool.max-idle=8spring.redis.pool.min-idle=0spring.redis.pool.max-active=8spring.redis.pool.max-wait=-1# name of Redis server#spring.redis.sentinel.master=# comma-separated list of host:port pairs#spring.redis.sentinel.nodes=spring.session.store-type=redis
3.在springboot启动文件类上加入注解
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1200,redisNamespace="xxxx")
其中1200redis中session过期时间
并在启动文件中注入 session策略 这个策略是我自己实现的
@Bean
public HttpSessionStrategy httpSessionStrategy() {
// return new MyHeaderHttpSessionStrategy(); // 这是原来的策略 HeaderHttpSessionStrategy()
return new MyCookieHttpSessionStrategy(); // 这是原来的策略 CookieHttpSessionStrategy();
//
}
public HttpSessionStrategy httpSessionStrategy() {
// return new MyHeaderHttpSessionStrategy(); // 这是原来的策略 HeaderHttpSessionStrategy()
return new MyCookieHttpSessionStrategy(); // 这是原来的策略 CookieHttpSessionStrategy();
//
}
4.MyHeaderHttpSessionStrategy:
package com.taibang.logisticsmanager.config;import java.util.concurrent.TimeUnit;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.session.Session;import org.springframework.session.web.http.HttpSessionStrategy;import org.springframework.util.Assert;/** * 自方法只能从请求头中读取sessionid * 请求头中的信息作为中间件 * @author Dream * */public class MyHeaderHttpSessionStrategy implements HttpSessionStrategy { @Autowiredprivate RedisTemplate redisTemplate;private String headerName = "CAS_USER";//每次请求的请求头名称 private String defaultSessionId = "default-sessionid";public String getRequestedSessionId(HttpServletRequest request) {System.out.println("测试CAS_USER:"+request.getHeader("CAS_USER"));ValueOperations<String, String> vops = redisTemplate.opsForValue();System.out.println("vops1:"+vops);String sessionid = request.getHeader("CAS_USER");System.out.println("redis中sessionid"+sessionid); if (sessionid != null && !sessionid.equals("")) { String jsessionid = vops.get(sessionid); if(jsessionid!=null){ boolean flag =redisTemplate.expire(sessionid, 60*10, TimeUnit.SECONDS); System.out.println("flag:"+flag); } return jsessionid; } else { System.out.println("返回默认sessionid"+sessionid); return vops.get(sessionid); }}public void onNewSession(Session session, HttpServletRequest request,HttpServletResponse response) {String jsessionid = request.getHeader("CAS_USER");String sessionid = session.getId();System.out.println("创建sessionid:"+sessionid); ValueOperations<String, String> vops = redisTemplate.opsForValue(); System.out.println("创建sessionvops2:"+vops); if (jsessionid != null && !jsessionid.equals("")) { //保存xxx和sessionid映射关系 vops.set(jsessionid, sessionid); boolean flag= redisTemplate.expire(jsessionid, 60*10, TimeUnit.SECONDS); System.out.println("flag:"+flag); }else{ //没有传xxx时,保存为默认 vops.set(jsessionid, sessionid); redisTemplate.expire(jsessionid, 60*10, TimeUnit.SECONDS); }response.setHeader(this.headerName, jsessionid);}public void onInvalidateSession(HttpServletRequest request,HttpServletResponse response) {System.out.println("注销session");String jsessionid = request.getHeader("CAS_USER"); redisTemplate.expire(jsessionid, 0, TimeUnit.SECONDS);response.setHeader(this.headerName, "");}/** * The name of the header to obtain the session id from. Default is "x-auth-token". * * @param headerName the name of the header to obtain the session id from. */public void setHeaderName(String headerName) {Assert.notNull(headerName, "headerName cannot be null");this.headerName = headerName;}}
5: MyCookieHttpSessionStrategy();因为项目需要两个登陆入口,如果不使用nigix服务器,没有了请求头,就没有办法管理,所有就写了这个 保留了cookie的机制
package com.taibang.logisticsmanager.config;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.HashSet;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.Set;import java.util.StringTokenizer;import java.util.concurrent.TimeUnit;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.session.Session;import org.springframework.session.web.http.CookieHttpSessionStrategy;import org.springframework.session.web.http.CookieSerializer;import org.springframework.session.web.http.CookieSerializer.CookieValue;import org.springframework.session.web.http.DefaultCookieSerializer;import org.springframework.session.web.http.HttpSessionManager;import org.springframework.session.web.http.MultiHttpSessionStrategy;import org.springframework.util.Assert;/** * 自定义策略,有请求头,从请求头读取sessionid信息,无请求头使用cookie的策略 * @author Dream * */public final class MyCookieHttpSessionStrategy implements MultiHttpSessionStrategy, HttpSessionManager{/** * The default delimiter for both serialization and deserialization. */private static final String DEFAULT_DELIMITER = " ";private static final String SESSION_IDS_WRITTEN_ATTR = MyCookieHttpSessionStrategy.class.getName().concat(".SESSIONS_WRITTEN_ATTR");static final String DEFAULT_ALIAS = "0";static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s";private static final Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME;private CookieSerializer cookieSerializer = new DefaultCookieSerializer();/** * The delimiter between a session alias and a session id when reading a cookie value. * The default value is " ". */private String deserializationDelimiter = DEFAULT_DELIMITER;/** * The delimiter between a session alias and a session id when writing a cookie value. * The default is " ". */private String serializationDelimiter = DEFAULT_DELIMITER;private String headerName = "CAS_USER";//此处请求头名成可修改@Autowiredprivate RedisTemplate redisTemplate;public String getRequestedSessionId(HttpServletRequest request) {ValueOperations<String, String> vops = redisTemplate.opsForValue();String sessionid = request.getHeader("CAS_USER"); if (sessionid != null && !sessionid.equals("")) { String jsessionid = vops.get(sessionid); if(jsessionid!=null){ boolean flag =redisTemplate.expire(sessionid, 60*10, TimeUnit.SECONDS); } return jsessionid; }Map<String, String> sessionIds = getSessionIds(request);String sessionAlias = getCurrentSessionAlias(request);return sessionIds.get(sessionAlias);}public String getCurrentSessionAlias(HttpServletRequest request) {if (this.sessionParam == null) {return DEFAULT_ALIAS;}String u = request.getParameter(this.sessionParam);if (u == null) {return DEFAULT_ALIAS;}if (!ALIAS_PATTERN.matcher(u).matches()) {return DEFAULT_ALIAS;}return u;}public String getNewSessionAlias(HttpServletRequest request) {Set<String> sessionAliases = getSessionIds(request).keySet();if (sessionAliases.isEmpty()) {return DEFAULT_ALIAS;}long lastAlias = Long.decode(DEFAULT_ALIAS);for (String alias : sessionAliases) {long selectedAlias = safeParse(alias);if (selectedAlias > lastAlias) {lastAlias = selectedAlias;}}return Long.toHexString(lastAlias + 1);}private long safeParse(String hex) {try {return Long.decode("0x" + hex);}catch (NumberFormatException notNumber) {return 0;}}public void onNewSession(Session session, HttpServletRequest request,HttpServletResponse response) {String jsessionid = request.getHeader("CAS_USER");String sessionid = session.getId(); ValueOperations<String, String> vops = redisTemplate.opsForValue(); if (jsessionid != null && !jsessionid.equals("")) { //保存xxx和sessionid映射关系 vops.set(jsessionid, sessionid); boolean flag= redisTemplate.expire(jsessionid, 60*10, TimeUnit.SECONDS); return; }Set<String> sessionIdsWritten = getSessionIdsWritten(request);if (sessionIdsWritten.contains(session.getId())) {return;}sessionIdsWritten.add(session.getId());Map<String, String> sessionIds = getSessionIds(request);String sessionAlias = getCurrentSessionAlias(request);sessionIds.put(sessionAlias, session.getId());String cookieValue = createSessionCookieValue(sessionIds);this.cookieSerializer.writeCookieValue(new CookieValue(request, response, cookieValue));}@SuppressWarnings("unchecked")private Set<String> getSessionIdsWritten(HttpServletRequest request) {Set<String> sessionsWritten = (Set<String>) request.getAttribute(SESSION_IDS_WRITTEN_ATTR);if (sessionsWritten == null) {sessionsWritten = new HashSet<String>();request.setAttribute(SESSION_IDS_WRITTEN_ATTR, sessionsWritten);}return sessionsWritten;}private String createSessionCookieValue(Map<String, String> sessionIds) {if (sessionIds.isEmpty()) {return "";}if (sessionIds.size() == 1 && sessionIds.keySet().contains(DEFAULT_ALIAS)) {return sessionIds.values().iterator().next();}StringBuffer buffer = new StringBuffer();for (Map.Entry<String, String> entry : sessionIds.entrySet()) {String alias = entry.getKey();String id = entry.getValue();buffer.append(alias);buffer.append(this.serializationDelimiter);buffer.append(id);buffer.append(this.serializationDelimiter);}buffer.deleteCharAt(buffer.length() - 1);return buffer.toString();}public void onInvalidateSession(HttpServletRequest request,HttpServletResponse response) {if(request.getHeader("CAS_USER")!=null) {String jsessionid = request.getHeader("CAS_USER"); redisTemplate.expire(jsessionid, 0, TimeUnit.SECONDS);}else {Map<String, String> sessionIds = getSessionIds(request);String requestedAlias = getCurrentSessionAlias(request);sessionIds.remove(requestedAlias);String cookieValue = createSessionCookieValue(sessionIds);this.cookieSerializer.writeCookieValue(new CookieValue(request, response, cookieValue));}}public void setHeaderName(String headerName) {Assert.notNull(headerName, "headerName cannot be null");this.headerName = headerName;}/** * Sets the name of the HTTP parameter that is used to specify the session alias. If * the value is null, then only a single session is supported per browser. * * @param sessionAliasParamName the name of the HTTP parameter used to specify the * session alias. If null, then ony a single session is supported per browser. */public void setSessionAliasParamName(String sessionAliasParamName) {this.sessionParam = sessionAliasParamName;}/** * Sets the {@link CookieSerializer} to be used. * * @param cookieSerializer the cookieSerializer to set. Cannot be null. */public void setCookieSerializer(CookieSerializer cookieSerializer) {Assert.notNull(cookieSerializer, "cookieSerializer cannot be null");this.cookieSerializer = cookieSerializer;}/** * Sets the name of the cookie to be used. * @param cookieName the name of the cookie to be used * @deprecated use {@link #setCookieSerializer(CookieSerializer)} */@Deprecatedpublic void setCookieName(String cookieName) {DefaultCookieSerializer serializer = new DefaultCookieSerializer();serializer.setCookieName(cookieName);this.cookieSerializer = serializer;}/** * Sets the delimiter between a session alias and a session id when deserializing a * cookie. The default is " " This is useful when using * <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a> for writing the cookies * which doesn't allow for spaces in the cookie values. * * @param delimiter the delimiter to set (i.e. "_ " will try a delimeter of either "_" * or " ") */public void setDeserializationDelimiter(String delimiter) {this.deserializationDelimiter = delimiter;}/** * Sets the delimiter between a session alias and a session id when deserializing a * cookie. The default is " ". This is useful when using * <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a> for writing the cookies * which doesn't allow for spaces in the cookie values. * * @param delimiter the delimiter to set (i.e. "_") */public void setSerializationDelimiter(String delimiter) {this.serializationDelimiter = delimiter;}public Map<String, String> getSessionIds(HttpServletRequest request) {List<String> cookieValues = this.cookieSerializer.readCookieValues(request);String sessionCookieValue = cookieValues.isEmpty() ? "": cookieValues.iterator().next();Map<String, String> result = new LinkedHashMap<String, String>();StringTokenizer tokens = new StringTokenizer(sessionCookieValue,this.deserializationDelimiter);if (tokens.countTokens() == 1) {result.put(DEFAULT_ALIAS, tokens.nextToken());return result;}while (tokens.hasMoreTokens()) {String alias = tokens.nextToken();if (!tokens.hasMoreTokens()) {break;}String id = tokens.nextToken();result.put(alias, id);}return result;}public HttpServletRequest wrapRequest(HttpServletRequest request,HttpServletResponse response) {request.setAttribute(HttpSessionManager.class.getName(), this);return request;}public HttpServletResponse wrapResponse(HttpServletRequest request,HttpServletResponse response) {return new MultiSessionHttpServletResponse(response, request);}public String encodeURL(String url, String sessionAlias) {String encodedSessionAlias = urlEncode(sessionAlias);int queryStart = url.indexOf("?");boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias);if (queryStart < 0) {return isDefaultAlias ? url: url + "?" + this.sessionParam + "=" + encodedSessionAlias;}String path = url.substring(0, queryStart);String query = url.substring(queryStart + 1, url.length());String replacement = isDefaultAlias ? "" : "$1" + encodedSessionAlias;query = query.replaceFirst("((^|&)" + this.sessionParam + "=)([^&]+)?",replacement);String sessionParamReplacement = String.format("%s=%s", this.sessionParam,encodedSessionAlias);if (!isDefaultAlias && !query.contains(sessionParamReplacement)&& url.endsWith(query)) {// no existing aliasif (!(query.endsWith("&") || query.length() == 0)) {query += "&";}query += sessionParamReplacement;}return path + "?" + query;}private String urlEncode(String value) {try {return URLEncoder.encode(value, "UTF-8");}catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}}/** * A {@link CookieHttpSessionStrategy} aware {@link HttpServletResponseWrapper}. */class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {private final HttpServletRequest request;MultiSessionHttpServletResponse(HttpServletResponse response,HttpServletRequest request) {super(response);this.request = request;}private String getCurrentSessionAliasFromUrl(String url) {String currentSessionAliasFromUrl = null;int queryStart = url.indexOf("?");if (queryStart >= 0) {String query = url.substring(queryStart + 1);Matcher matcher = Pattern.compile(String.format("%s=([^&]+)",MyCookieHttpSessionStrategy.this.sessionParam)).matcher(query);if (matcher.find()) {currentSessionAliasFromUrl = matcher.group(1);}}return currentSessionAliasFromUrl;}@Overridepublic String encodeRedirectURL(String url) {String encodedUrl = super.encodeRedirectURL(url);String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl);String alias = (currentSessionAliasFromUrl != null)? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request);return MyCookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias);}@Overridepublic String encodeURL(String url) {String encodedUrl = super.encodeURL(url);String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl);String alias = (currentSessionAliasFromUrl != null)? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request);return MyCookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias);}}}3.最终还是把问题解决,这个是某智教育公司的nigix服务器,人家就是不转发cookie,人后把我们项目所有人都坑了,还以为是我们自己代码有问题,第一次写博客,大神勿喷,多多指教。
4.在这位仁兄的博客上也学习到了很多 http://blog.csdn.net/qq351790934/article/details/54930049
阅读全文
1 0
- springboot利用springsession实现redis共享session,并且自定义sessionid
- SpringBoot(八)SpringBoot整合springsession实现分布式session共享
- mybatis+spring+springmvc+springsession + redis实现session共享配置
- springmvc+springsession实现session共享
- Redis SpringSession+Redis实现分布式Session存储
- spring-session实现分布式session共享及自定义sessionid
- SpringSession实现session共享--简单配置
- SpringSession和Redis实现Session跨域
- 基于SpringBoot,SpringSession和redis的会话共享
- SpringSession集成redis实现session共享(No bean named 'springSessionRepositoryFilter' available)
- springboot整合redis,实现session共享
- springboot(七)redis 实现session共享
- vue+axios+springboot+redis 实现session 共享
- 使用springboot+redis实现session共享
- springboot + redis集群实现session共享
- SpringSession使用redis存储HttpSession(共享session)
- 利用redis实现tomcat session共享
- 利用tomcat redis 实现session共享
- mysql 模糊查询LIKE 在tp中使用
- S1001 无休止的 Calculate A+B
- C#——继承
- tomcat服务已经开启,自己可以访问但是同网段其他机器无法访问解决办法
- eclipse环境import工程出现中文乱码问题的解决方案
- springboot利用springsession实现redis共享session,并且自定义sessionid
- xml4种解析方法性能比较
- 测试计划2
- FastJson对JodaTime的处理
- 整合Spring时Service层为什么不做全局包扫描详解
- 服务器端设计的思想、方法及应用
- Java微信支付全教程demo【公众号支付】
- live555 调优总结
- turtlebot3_Python脚本控制运行