springboot利用springsession实现redis共享session,并且自定义sessionid
2017-12-01 16:25
1551 查看
一、初衷
作为一个刚入行的小白,在公司接手了一个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>
2. 在配置文件application.properties中加入参数
# database name spring.redis.database=0 # server host1 spring.redis.host=********** //redis服务器ip # server password #spring.redis.password= //redis服务器密码 默认是没有的 #connection port spring.redis.port=6379 //redis服务器端口号 # pool settings ... spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.pool.max-active=8 spring.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();
//
}
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 { @Autowired private 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; i bef7 mport 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";//此处请求头名成可修改 @Autowired private 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)} */ @Deprecated public 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 alias if (!(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; } @Override public 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); } @Override public 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
相关文章推荐
- 使用springboot+redis实现session共享
- spring boot + redis 实现session共享
- 使用springboot+redis实现session共享
- Spring Boot系列(七)Spring Boot使用Redis实现session共享
- 使用springboot+redis实现session共享
- springboot 集成redis实现session共享
- Spring Boot系列(七)Spring Boot使用Redis实现session共享
- 使用springboot+redis实现session共享
- 利用spring-session 和 redis 实现简单的session共享
- 使用springboot+redis实现session共享
- Spring boot + redis 实现session 共享管理
- 使用springboot+redis实现session共享
- spring boot + redis 实现session共享
- SpringBoot+redis 实现shiro集群,共享session。亲测可用
- spring boot + redis 实现session共享
- Spring Boot系列(七)Spring Boot使用Redis实现session共享
- vue+axios+springboot+redis 实现session 共享
- spring boot + redis 实现session共享
- springboot整合redis,实现session共享
- SpringBoot+Redis+Nginx实现负载均衡以及Session缓存共享