分布式环境下用redis模拟session
来源:互联网 发布:南风知我意琰阙百度云 编辑:程序博客网 时间:2024/06/07 12:18
首先为什么使用redis?
因为分布式有不同服务器的缘故,如果你安照一般方式存储session,那么你的session会保存在某一台服务器上,如果你的下一个请求并不是访问这台服务器,那么会发生读取不到session的情况
redis存储的实现方案:
第一种 是使用容器拓展来实现,一般都是通过容器插件来实现,例如基于Tomcat的tomcat-redis-session-manager,基于Jetty的jetty-session-redis等等。好处是对项目来说是透明的,无需更改代码,但是目前还不支持Tomcat8。个人觉得由于过于依赖容器,,一旦更换容器或者容器升级,那又得重新来过。而且代码并不在项目中,对于开发者的维护也是个麻烦。
第二种 是自定义会话管理的工具类,这样的话灵活性很大,可以根据自身需求来实现,但是需要额外的开发时间
第三种是使用框架的会话管理工具,例如spring-session,shiro等,可以理解是替换了servlet那一套会话管理,不依赖容器,不用改动代码。如果采用spring-session的话,使用的是spring-data-redis那一套连接池,prefect,不过前提是你得用spring框架。至于shiro,那是一个十分成熟,强大易用的安全框架,学习成本比spring-session来的要多一些。
下面我们介绍一下第二种方式的实现
要注意的是为什么前端用ajax的方式登录,因为把模拟的session信息用存到redis后,需要在本地存入userId和token来作为用户的标识,通过这个标识去redis里验证该用户是否登录,从而获取redis中的用户登录信息,但是分布式中多个系统对应多个domain,所以login模块生成的userId和token要想每个系统都用,必须每个系统都生成自己的cookie信息,java端无法为每个系统生成一份cookie所以只能在前端用iframe的方式为每个系统生成一份cookie
下面是详细代码
redis的配置:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.7.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- redis缓存部分 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="maxWaitMillis" value="${redis.maxWaitMillis}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig" /> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory" /> </bean> <!--加载redis --> <bean id="redisService" class="com.maigangle.b2b.common.redis.RedisSpringServiceImpl"> <!-- 控制redis开关 --> <property name="isUse" value="true"></property> </bean></beans>
RedisSpringServiceImpl.java
package com.maigangle.b2b.common.redis;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.RedisConnectionFailureException;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import com.alibaba.fastjson.JSON;import com.maigangle.b2b.common.exception.CommonException;/** * redis接口实现 * * @author * @since * @version 1.0 * */public class RedisSpringServiceImpl implements RedisSpringService { private static String redisCode = "utf-8"; private boolean isUse; // redis开关 private byte[] getBytes(String str) { try { return str.getBytes(redisCode); } catch (UnsupportedEncodingException e) { return str.getBytes(); } } public boolean isUse() { return isUse; } public void setIsUse(boolean isUse) { this.isUse = isUse; } @Autowired private RedisTemplate<String, String> redisTemplate; public void pub(String channel, String param) { if (!isUse) return; redisTemplate.convertAndSend(channel, param); } /** * @param key */ public Long del(final String... keys) { if (!isUse) return null; try { long re = redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { long result = 0; for (int i = 0; i < keys.length; i++) { result = connection.del(keys[i].getBytes()); result++; } return result; } }); return re; } catch (Exception e) { return null; } } /** * @param key * @param value * @param liveTime */ public void set(final byte[] key, final byte[] value, final long liveTime) { if (!isUse) return; try { redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.set(key, value); if (liveTime > 0) { connection.expire(key, liveTime); } return 1L; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); } } /** * @param key * @param value * @param liveTime */ public void set(String key, String value, long liveTime) { this.set(getBytes(key), getBytes(value), liveTime); } /** * @param key * @param liveTime */ public boolean expire(String key, long liveTime) { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.expire(key.getBytes(), liveTime); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @param key * @param value */ public void set(String key, String value) { this.set(key, value, 0L); } /** * @param key * @param value */ public void set(byte[] key, byte[] value) { this.set(key, value, 0L); } /** * @param key * @param value */ public void set(String key, byte[] value) { this.set(getBytes(key), value, 0L); } /** * */ @Override public void setOjb(String key, Object value, long time) { this.set(getBytes(key), getBytes(JSON.toJSONString(value)), time); } /** * @param key * @return */ public String get(final String key) { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection connection) throws DataAccessException { try { byte[] bytes = connection.get(getBytes(key)); if (bytes == null || bytes.length == 0) { return null; } return new String(bytes, redisCode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (Exception e1) { e1.printStackTrace(); return null; } return ""; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } public byte[] get4byte(final String key) { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<byte[]>() { public byte[] doInRedis(RedisConnection connection) throws DataAccessException { try { return connection.get(getBytes(key)); } catch (Exception e1) { e1.printStackTrace(); return null; } } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } @Override public <T> T getObj(String key, Class<T> elementType) { String jsonString = this.get(key); T obj; obj = JSON.parseObject(jsonString, elementType); if (obj == null) { try { obj = elementType.newInstance();// 防止空指针异常 } catch (InstantiationException | IllegalAccessException e) { throw new CommonException("get redis error:", e); } } return obj; } /** * @param pattern * @return */ public void Setkeys(String pattern) { if (!isUse) return; try { redisTemplate.keys(pattern); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); } } /** * @param key * @return */ public boolean exists(final String key) { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.exists(getBytes(key)); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @return */ // public String flushDB() { // if(!isUse) return null; // return redisTemplate.execute(new RedisCallback<String>() { // public String doInRedis(RedisConnection connection) throws // DataAccessException { // connection.flushDb(); // return "ok"; // } // }); // } public boolean flushDB() { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return true; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @return */ public long dbSize() { if (!isUse) return 0; try { return redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return 0; } } /** * @return */ public String ping() { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection connection) throws DataAccessException { return connection.ping(); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } private void closeSwitch(Exception e) { if (e instanceof RedisConnectionFailureException) { this.isUse = false; } } /** * submit check token * * @param token * @return */ public boolean checkToken(String token) { if (StringUtils.isBlank(token)) { return false; } Object tk = this.get(token); if (tk != null) { this.del(token); return true; } return false; } @Override public void setHm(String key, Map<String, String> map, long liveTime) { if (!isUse) return; final Map<byte[], byte[]> hashes = new LinkedHashMap<byte[], byte[]>(map.size()); for (Map.Entry<String, String> entry : map.entrySet()) { hashes.put(getBytes(entry.getKey()), getBytes(entry.getValue())); } redisTemplate.execute(new RedisCallback<Object>() { public Object doInRedis(RedisConnection connection) { connection.hMSet(getBytes(key), hashes); if (liveTime > 0) { connection.expire(getBytes(key), liveTime); } return null; } }, true); } @Override public Map<String, String> getHm(String key) { final byte[] rawKey = getBytes(key); Map<byte[], byte[]> entries = redisTemplate.execute(new RedisCallback<Map<byte[], byte[]>>() { public Map<byte[], byte[]> doInRedis(RedisConnection connection) { return connection.hGetAll(rawKey); } }, true); Map<String, String> map = new LinkedHashMap<String, String>(entries.size()); for (Map.Entry<byte[], byte[]> entry : entries.entrySet()) { try { map.put(new String(entry.getKey(), redisCode), new String(entry.getValue(), redisCode)); } catch (UnsupportedEncodingException e) { return new HashMap<String, String>(); } } return map; } @Override public void setList(String key, List<String> list, long liveTime) { if (!isUse) return; final List<byte[]> listes = new ArrayList<byte[]>(list.size()); for (String value : list) { listes.add(getBytes(value)); } redisTemplate.execute(new RedisCallback<Object>() { public Object doInRedis(RedisConnection connection) { for (byte[] bs : listes) { connection.rPush(getBytes(key), bs); } if (liveTime > 0) { connection.expire(getBytes(key), liveTime); } return null; } }, true); } @Override public List<String> getList(String key) { final byte[] rawKey = getBytes(key); List<byte[]> entries = redisTemplate.execute(new RedisCallback<List<byte[]>>() { public List<byte[]> doInRedis(RedisConnection connection) { return connection.lRange(rawKey, 0, -1); } }, true); List<String> list = new ArrayList<String>(entries.size()); for (byte[] entry : entries) { try { list.add(new String(entry, redisCode)); } catch (UnsupportedEncodingException e) { return new ArrayList<String>(); } } return list; }}
接口: RedisSpringService.java
package com.maigangle.b2b.common.redis;import java.util.List;import java.util.Map;/** * redis对外提供服务接口,如需使用请先注入(基于spring) * * @author 朱晗 * @since 2016年11月28日 上午8:41:45 * @version 1.0 * */public interface RedisSpringService { /** * 发布消息 * */ public abstract void pub(String channel, String param); /** * 通过key删除 * * @param key */ public abstract Long del(String... keys); /** * 添加key value 并且设置存活时间(byte) * * @param key * @param value * @param liveTime */ public abstract void set(byte[] key, byte[] value, long liveTime); /** * 添加key value 并且设置存活时间 * * @param key * @param value * @param liveTime * 单位秒 */ public abstract void set(String key, String value, long liveTime); /** * 设置key过期时间 * * @param key * @param liveTime * @return */ public abstract boolean expire(String key, long liveTime); /** * 添加key value * * @param key * @param value */ public abstract void set(String key, String value); /** * 添加key value * * @param key * @param value */ public abstract void set(String key, byte[] value); /** * 添加key value (字节)(序列化) * * @param key * @param value */ public abstract void set(byte[] key, byte[] value); /** * 保存对象 * * @param key * @param value */ public abstract void setOjb(final String key, Object value, long time); /** * 获取redis value (String) * * @param key * @return */ public abstract String get(String key); public abstract byte[] get4byte(String key); /** * 得到对象 * * @param key * @param elementType * @return */ public abstract <T> T getObj(final String key, Class<T> elementType); /** * 通过正则匹配keys * * @param pattern * @return */ public abstract void Setkeys(String pattern); /** * 检查key是否已经存在 * * @param key * @return */ public abstract boolean exists(String key); /** * 清空redis 所有数据 * * @return */ // public abstract String flushDB(); public abstract boolean flushDB(); /** * 查看redis里有多少数据 */ public abstract long dbSize(); /** * 检查是否连接成功 * * @return */ public abstract String ping(); /** * submit check token * * @param token * @return */ public boolean checkToken(String token); /** * * @author 朱晗 * @since 2017年6月7日 上午8:45:55 * @param key * @param map * @param liveTime */ public void setHm(String key, Map<String, String> map, long liveTime); /** * * @author 朱晗 * @since 2017年6月7日 上午8:45:58 * @param key * @return */ public Map<String, String> getHm(String key); /** * * @author 朱晗 * @since 2017年6月7日 上午8:46:50 * @param key * @param list * @param liveTime */ public void setList(String key, List<String> list, long liveTime); /** * * @author 朱晗 * @since 2017年6月7日 上午8:46:55 * @param key * @return */ public List<String> getList(String key);}
前端:
login.js
$('#loginIn').click(function(event) { var $this = $(this); var acc = $('#account').val(); var pw = $('#password').val(); var loadUrl = util.get('redirectURL'); var loginValid = $("#loginForm").valid(); var setHtml = ''; var loginUrl = ''; // 如果返回false 设置为空 if (loadUrl === false) { loadUrl = ''; } if(loginValid) { $this.text('正在登录...'); $this.attr('disabled', true); $.ajax({ url: apiPath + '/auth/ajaxDoLogin', type: 'post', data: { account: acc, passwd: pw, redirectURL: loadUrl }, success: function(data) { if (data.isVaild) { if(data.role === 'A'){ setHtml += '<iframe src="' + gangUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ +'"></iframe>'; setHtml += '<iframe src="' + payUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + orderUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + homeUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + cartUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + cangkuUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + fundUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + regUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + baikeUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + helpUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; setHtml += '<iframe src="' + indexUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; }else if(data.role === 'B'){ setHtml += '<iframe src="' + cangkuUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; }else if(data.role === 'C'){ setHtml += '<iframe src="' + mcUrlBase + '/api/common/setCookie?_it_=' + data._it_ + '&_token_='+ data._token_ + '"></iframe>'; } if(data.isNotBindPhone) { window.location.href = data.redirectURL + '?firmId=' + data.firmId; } else { // 添加iframe执行写入cookie $('#setCookieView').html(setHtml); setTimeout(function() { window.location.href = data.redirectURL; }, 2000); } } else { $('#accError').show(); $('#accError').text(data.msg); $this.text('我同意交易规则,登录'); $this.attr('disabled', false); } }, error: function(msg){ $('#accError').show(); $('#accError').text('登录失败!'); $this.text('我同意交易规则,登录'); $this.attr('disabled', false); } }); } });
后端java代码
@RequestMapping(value = "/ajaxDoLogin") @ResponseBody public Map<String, Object> ajaxDoLogin( HttpServletRequest request, HttpServletResponse response, String account, String passwd, String redirectURL) { String logBatch = LogBatchUtil.getLogUUID(EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); Map<String, Object> resultMap = new HashMap<String, Object>(); try { super.logInfo( request, logBatch, "登录", "进入登录相关数据,account:" + account + ",redirectURL:" + redirectURL, EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); account = account.replaceAll(" ", ""); // 登录验证 Map<String, Object> vaildMap = validateLogin(request, account, passwd); boolean isVaild = (boolean) vaildMap.get("isVaild"); if (!isVaild) { return vaildMap; } // 手机登录/交易商登录 if (loginService.countByMobile(account) == 0) { resultMap = firmIdLogin(request, response, logBatch, account, passwd, redirectURL);// 账号为交易号 } else { resultMap = mobileLogin(request, response, logBatch, account, passwd, redirectURL);// 账号为手机号码 } return resultMap; } catch (Exception e) { e.printStackTrace(); super.logError( request, logBatch, "账号为:" + account + "会员登录失败", "交易商ID为:" + getFirmId(request) + "错误信息为:" + ExceptionUtils.getStackTrace(e), Boolean.getBoolean(redisSpringService.get(EnumMonitorLog.LOG_NOTIFY_SWITCH.getKey())), EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); resultMap.put("msg", "非法登录"); resultMap.put("isVaild", false); return resultMap; } }private Map<String, Object> firmIdLogin(HttpServletRequest request, HttpServletResponse response, String logBatch, String account, String passwd, String redirectURL) { AcntUserBasic acntUserBasic = null; Map<String, Object> resultMap = null; // 账号为交易号 if (!loginApi(request, logBatch, account, passwd)) { return this.setLoginError(account, passwd); } acntUserBasic = loginService.selectByFirmId(account); if (acntUserBasic != null && !StringUtils.equals(acntUserBasic.getIsLock(), IsLockEnum.IS_LOCK_N.getKey())) { return this.setLockError(account, passwd, "登录帐号" + account + IsLockEnum.getLockInfo(acntUserBasic.getIsLock())); } // 用户基本信息不存在或手机号为空(后台新增用户) if (acntUserBasic == null || StringUtils.isBlank(acntUserBasic.getMobile())) { // 绑定手机号 resultMap = new HashMap<String, Object>(); resultMap.put("isVaild", true); resultMap.put("isNotBindPhone", true); resultMap.put("redirectURL", super.getUrl(AuthUrlConstant.LOGIN_URL) + "/auth/bindPhoneFirst"); resultMap.put("firmId", account); return resultMap; } super.logInfo(request, logBatch, "会员登录", "通过pc端进行登录认证," + "账号为:" + account + "会员认证成功", EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); String token = UUIDUtil.getRandomUUID();// 登录token setLoginInfo(request, response, acntUserBasic, logBatch, account, token); resultMap = redirectToURL(acntUserBasic.getUserId(), acntUserBasic.getUserRole(), redirectURL, token); resultMap.put("role", acntUserBasic.getUserRole());//返回用户角色 return resultMap; }private void setLoginInfo( HttpServletRequest request, HttpServletResponse response, AcntUserBasic acntUserBasic, String logBatch, String account, String token) { super.logInfo(request, logBatch, "模拟session", "通过pc端进行登录,开始模拟session" + "账号为:" + account, EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); String apiToken = UUIDUtil.getRandomUUID(); List<String> dptIds = null; // 用户权限为仓管时查询该用户的仓库 if (StringUtils.equals(acntUserBasic.getUserRole(), USER_ROLE_B)) { List<AcntDepotRel> acntDepotRels = loginService.findAcntDepotRelsByFirmId(acntUserBasic.getFirmId()); if (acntDepotRels != null && acntDepotRels.size() > 0) { dptIds = new ArrayList<String>(); for (AcntDepotRel acntDepotRel : acntDepotRels) { dptIds.add(acntDepotRel.getDptId()); } } } String isCert = acntUserBasic.getIsCert(); if (StringUtils.equals(isCert, YesOrNoEnum.NO.getKey())) { AcntUserCert acntUserCert = new AcntUserCert(); acntUserCert.setUserId(acntUserBasic.getUserId()); if (loginService.countAcntUserCert(acntUserCert) == 0) { isCert = CertStatusEnum.CERTSTATUS_S.getKey();// 没有认证 if (loginService.countAcntUserCertFail(acntUserCert) > 0) { isCert = CertStatusEnum.CERTSTATUS_X.getKey();// 认证不通过 } } else { acntUserCert = loginService.getOneAcntUserCert(acntUserCert); isCert = acntUserCert.getCertStatus(); } } AcntUserMall acntUserMall = loginService.selectAcntUserMallByFirmId(acntUserBasic.getFirmId()); String company = ""; if (acntUserMall != null) { company = acntUserMall.getCompany(); } // 模拟session登录成功 setSimulateSession( request, acntUserBasic.getUserId(), acntUserBasic.getMobile(), acntUserBasic.getFirmId(), acntUserBasic.getUserType(), acntUserBasic.getUserRole(), company, isCert, dptIds, loginService.selectPrivCodeByFirmId(acntUserBasic.getFirmId()), apiToken, token); // 设置cookie CookieUtils.setCookie(request, response, CookieConstant.PUT_USERID_NAME, EncryptUtils.encrypt(acntUserBasic.getUserId()), 0); // 设置登录token CookieUtils.setCookie(request, response, CookieConstant.PUT_TOKEN_INFO, token, 0); loginService.insertAcntUserLogin(IpUtil.getIpAddr(request), acntUserBasic.getUserId(), acntUserBasic.getUserRole()); // 插入uvId userId关系 RequestUvUserRel requestUvUserRel = new RequestUvUserRel(); requestUvUserRel.setUserId(acntUserBasic.getUserId()); requestUvUserRel.setUvId(CookieUtils.getCookieValue(request, CookieConstant.UV_ID)); requestUvUserRel.setCreateTime(MongoDateUtil.getMongoDate(new Date())); loginService.insertRequestUvUserRel(requestUvUserRel); super.logInfo(request, logBatch, "模拟session", "通过pc端进行登录,模拟session成功" + "账号为:" + account, EnumMonitorLog.LOGSYSTEM_LOGIN.getKey()); }protected void setSimulateSession( HttpServletRequest request, String userId, String mobile, String firmId, String userType, String userRole, String company, String isCert, List<String> dptIds, List<String> privCodes, String apiToken, String token) { SessionInfo sessionInfo = new SessionInfo(); sessionInfo.setMobile(mobile); sessionInfo.setFirmId(firmId); sessionInfo.setUserType(userType); sessionInfo.setUserRole(userRole); sessionInfo.setCompanyName(company); sessionInfo.setLoginIp(IpUtil.getIpAddr(request)); sessionInfo.setUserId(userId); sessionInfo.setIsCert(isCert); sessionInfo.setApiToken(apiToken); sessionInfo.setDptIds(dptIds); sessionInfo.setPrivCodes(privCodes); sessionInfo.setToken(token); // 存放登录信息 redisService.setOjb(SessionConstant.SIMULATE_SESSION_NAME + userId, sessionInfo, 1800); // 设置apiToken时间为8小时 redisService.set(apiToken, "", 8 * 3600);// 默认8个小时 }
页面拦截器:
<mvc:interceptors> <!-- 登录认证 --> <mvc:interceptor> <mvc:mapping path="/rollGangPay/**" /> <mvc:mapping path="/rollImport/**" /> <mvc:mapping path="/rollManage/**" /> <mvc:mapping path="/rollPublish/**" /> <mvc:mapping path="/flatImport/**" /> <mvc:mapping path="/flatManage/**" /> <mvc:mapping path="/flatPriceModal/**" /> <!-- 需排除拦截的地址 --> <mvc:exclude-mapping path="/rollImport/uploadWare" /> <mvc:exclude-mapping path="/rollImport/importBendingWare" /> <mvc:exclude-mapping path="/flatImport/uploadWare" /> <mvc:exclude-mapping path="/flatImport/importBendingWare" /> <mvc:exclude-mapping path="/flatImport/stayPublishWare" /> <bean class="com.maigangle.b2b.common.web.interceptor.AuthLoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
拦截器类:AuthLoginInterceptor.java
package com.maigangle.b2b.common.web.interceptor;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import com.maigangle.b2b.common.base.SessionInfo;import com.maigangle.b2b.common.enums.CertStatusEnum;import com.maigangle.b2b.common.enums.UserRoleEnum;import com.maigangle.b2b.common.enums.YesOrNoEnum;import com.maigangle.b2b.common.redis.RedisSpringService;import com.maigangle.b2b.common.util.EncryptUtils;import com.maigangle.b2b.common.web.constants.AuthUrlConstant;import com.maigangle.b2b.common.web.constants.CookieConstant;import com.maigangle.b2b.common.web.constants.SessionConstant;import com.maigangle.b2b.common.web.util.CookieUtils;/** * 会员已经认证登录拦截(此文件请不要修改,如需修改请找相应的负责人) 后期要进行拆分保持功能解耦度更低 * * @author 朱晗 * @since 2016年11月28日 下午12:36:49 * @version 1.0 * */@Repositorypublic class AuthLoginInterceptor extends HandlerInterceptorAdapter { @Autowired RedisSpringService redisSpringService; private static final String HEADER = "x-requested-with"; private static final String XML_HTTP_REQUEST = "XMLHttpRequest"; private String isReferer = YesOrNoEnum.NO.getKey();// 是否referer跳转 private Map<String, String> excludedUrls;// 指定拦击地址到指定路径 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断userId是否为空 String userId = CookieUtils.getCookieValue(request, CookieConstant.PUT_USERID_NAME); System.out.println("userId:" + userId); if (StringUtils.isBlank(userId)) { return judgeAjaxJumpLogin(request, response); } // 判断userId是为正确的 userId = EncryptUtils.decrypt(userId); System.out.println("userId:" + userId); if (StringUtils.isBlank(userId)) { return judgeAjaxJumpLogin(request, response); } // 判断用户是否已登录 boolean existLogin = redisSpringService.exists(SessionConstant.SIMULATE_SESSION_NAME + userId); System.out.println("existLogin:" + existLogin); if (!existLogin) { return judgeAjaxJumpLogin(request, response); } // 判断用户是否已认证 SessionInfo sessionInfo = redisSpringService.getObj(SessionConstant.SIMULATE_SESSION_NAME + userId, SessionInfo.class); String isCert = sessionInfo.getIsCert(); if (!StringUtils.equals(isCert, CertStatusEnum.CERTSTATUS_Y.getKey())) { if (StringUtils.equals(isCert, CertStatusEnum.CERTSTATUS_N.getKey())) { // 认证中 return judgeAjaxJumpAuthIn(request, response); } else if (StringUtils.equals(isCert, CertStatusEnum.CERTSTATUS_X.getKey())) { // 认证不通过 return judgeAjaxJumpAuthNoPass(request, response); } else if (StringUtils.equals(isCert, CertStatusEnum.CERTSTATUS_S.getKey())) { // 没有认证 return judgeAjaxJumpAuthNo(request, response); } } // 判断是否有相应的商城交易权限 if (!StringUtils.equals(sessionInfo.getUserRole(), UserRoleEnum.DEALER.getKey())) { return judgeAjaxJumpRole(request, response); } // 判断网路环境是否变化 /* * String requestiIp = IpUtil.getIpAddr(request); * System.out.println("requestiIp:"+requestiIp); String loginIp = * redisSpringService.getObj(SessionConstant.SIMULATE_SESSION_NAME + * userId, SessionInfo.class).getLoginIp(); * System.out.println("loginIp:"+loginIp); if * (!requestiIp.equals(loginIp)) { return judgeAjaxJumpLogin(request, * response); } */ redisSpringService.expire(SessionConstant.SIMULATE_SESSION_NAME + userId, 1800); return true; } @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {} @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {} private boolean judgeAjaxJumpLogin(HttpServletRequest request, HttpServletResponse response) throws IOException { if (StringUtils.equals(isReferer, YesOrNoEnum.NO.getKey())) { if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", getReferLoginUrl(request)); return false; } else { response.sendRedirect(getRequestLoginUrl(request)); return false; } } else { String b2bLoginUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectURL = request.getHeader("referer"); // 获取referer是否为空,空直接跳转到登录界面 if (StringUtils.isNotBlank(redirectURL)) { if (excludedUrls != null && !excludedUrls.isEmpty()) { for (String key : excludedUrls.keySet()) { if (redirectURL.contains(key)) { redirectURL = redirectURL.replace(key, excludedUrls.get(key)); break; } } } String decodeUrl = URLEncoder.encode(redirectURL, "UTF-8"); String url = b2bLoginUrl + "?redirectURL=" + decodeUrl; if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", url); return false; } else { response.sendRedirect(url); return false; } } else { response.sendRedirect(getRequestLoginUrl(request)); return false; } } } /** * 没有认证 * * @author 王振光 * @since 2017年6月14日 上午11:07:40 * @param request * @param response * @return * @throws IOException */ private boolean judgeAjaxJumpAuthNo(HttpServletRequest request, HttpServletResponse response) throws IOException { String b2bAuthUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectUrl = b2bAuthUrl + "/userAuth/noAuth"; if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", redirectUrl); return false; } else { response.sendRedirect(redirectUrl); return false; } } /** * 认证中 * * @author 王振光 * @since 2017年6月14日 上午11:07:19 * @param request * @param response * @return * @throws IOException */ private boolean judgeAjaxJumpAuthIn(HttpServletRequest request, HttpServletResponse response) throws IOException { String b2bAuthUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectUrl = b2bAuthUrl + "/userAuth/inAuth"; if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", redirectUrl); return false; } else { response.sendRedirect(redirectUrl); return false; } } /** * 认证不通过 * * @author 王振光 * @since 2017年6月14日 上午11:07:49 * @param request * @param response * @return * @throws IOException */ private boolean judgeAjaxJumpAuthNoPass(HttpServletRequest request, HttpServletResponse response) throws IOException { String b2bAuthUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectUrl = b2bAuthUrl + "/userAuth/noPassAuth"; if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", redirectUrl); return false; } else { response.sendRedirect(redirectUrl); return false; } } /** * 角色错误提示<br> * * @author 王振光 * @since 2017年8月8日 上午9:51:31 * @param request * @param response * @return * @throws IOException */ private boolean judgeAjaxJumpRole(HttpServletRequest request, HttpServletResponse response) throws IOException { String b2bAuthUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectUrl = b2bAuthUrl + "/system/roleErr"; if (request.getHeader(HEADER) != null && request.getHeader(HEADER).equalsIgnoreCase(XML_HTTP_REQUEST)) { response.setHeader("sessionstatus", "interceptorErrpr"); // 响应头设置session状态 response.setHeader("redirectURL", redirectUrl); return false; } else { response.sendRedirect(redirectUrl); return false; } } private String getRequestLoginUrl(HttpServletRequest request) throws UnsupportedEncodingException { String b2bLoginUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectURL = request.getRequestURL().toString(); String query = request.getQueryString(); if (StringUtils.isNotBlank(query)) { redirectURL = redirectURL + "?" + query; } String decodeUrl = URLEncoder.encode(redirectURL, "UTF-8"); return b2bLoginUrl + "?redirectURL=" + decodeUrl; } private String getReferLoginUrl(HttpServletRequest request) throws UnsupportedEncodingException { String b2bLoginUrl = redisSpringService.getHm(AuthUrlConstant.B2B_AUTH_URL).get(AuthUrlConstant.LOGIN_URL); String redirectURL = request.getHeader("referer"); String decodeUrl = URLEncoder.encode(redirectURL, "UTF-8"); return b2bLoginUrl + "?redirectURL=" + decodeUrl; } public String getIsReferer() { return isReferer; } public void setIsReferer(String isReferer) { this.isReferer = isReferer; } public Map<String, String> getExcludedUrls() { return excludedUrls; } public void setExcludedUrls(Map<String, String> excludedUrls) { this.excludedUrls = excludedUrls; }}
- 分布式环境下用redis模拟session
- 集群/分布式环境下,Session处理策略
- 分布式环境下MySQL和Redis一致性
- redis 分布式 session容器
- Redis实现分布式环境下的分布式锁机制
- Redis实现分布式环境下的分布式锁机制
- Redis实现分布式环境下的分布式锁机制
- 集群环境下spring+session+redis,session共享问题
- 分布式中使用 Redis 实现 Session 共享(下)
- 分布式环境下session的存储的几个解决方案
- 集群/分布式环境下5种session处理策略
- 集群/分布式环境下5种session处理策略
- 集群/分布式环境下5种session处理策略
- 集群/分布式环境下5种session处理策略
- 集群、分布式环境下5种session处理策略
- 集群/分布式环境下5种session处理策略
- 分布式集群环境下Session共享的简单解决方案
- 集群/分布式环境下5种session处理策略
- //Dijkstra算法大连理工大学数据结构上机第四章
- 修改、删除表内容,增加列、修改列、删除列
- 地鼠的困境(SSL_1333)
- 深度学习—加快梯度下降收敛速度(二):Monmentum、RMSprop、Adam
- 1333 地鼠的困境
- 分布式环境下用redis模拟session
- RP8.1.0.3366企业版授权
- android进阶之了解Android系统与开机过程
- 【Chrome插件】使用FE助手-百度WEB前端助手
- PayPlugin的Payso层架构思路
- JavaScript类型转换
- WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-
- Spring核心一(基本概念)
- React Native的征程