apache shiro框架如何使用nginx负载
2017-07-21 15:26
513 查看
1.apache shiro框架在使用负载均衡的时候出现的问题
当我进入我的项目的首页的时候发现是无法登陆的,原因是因为服务器之间的session没有共享这也是Apache Shiro集群需要解决的问题。Apache Shiro集群要解决2个问题,一个是session的共享问题,一个是授权信息的cache共享问题,官网给的例子是Ehcache的实现。这里我们可以
通过集成redis来实现。
2.apache shiro集成redis。
这个比较简单。只需要引入相关的jar包,我项目里的redis是使用的哨兵模式。配置如下:redis的安装可以参考我之前写的文章。
3.apache shiro集群解决session共享的问题。
我们可以看DefaultWebSessionManager的源码,发现其父类DefaultSessionManager中有sessionDAO属性,这个属性是真正实现了session储存的类,这个就是我们自己实现的redis session的储存类。之前我在项目中使用的是EnterpriseCacheSessionDAO
<property name="sessionDAO">
<bean class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>
</property>
现在我们就要通过redis来实现了。
redisShiroSessionDAO:
/** * Created by Maggie on 2017/7/14. */ public class RedisSessionDAO extends AbstractSessionDAO { private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class); private ShiroSessionRepository shiroSessionRepository; public ShiroSessionRepository getShiroSessionRepository() { return shiroSessionRepository; } public void setShiroSessionRepository( ShiroSessionRepository shiroSessionRepository) { this.shiroSessionRepository = shiroSessionRepository; } @Override public void update(Session session) throws UnknownSessionException { getShiroSessionRepository().saveSession(session); } @Override public void delete(Session session) { getShiroSessionRepository().deleteSession(session.getId()); } //用来统计当前活动的session @Override public Collection<Session> getActiveSessions() { return shiroSessionRepository.getAllSessions(); } @Override protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); getShiroSessionRepository().saveSession(session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { return getShiroSessionRepository().getSession(sessionId); }
shiroSessionRepository:
/** * Created by Maggie on 2017/7/17. */ public class JedisShiroSessionRepository implements ShiroSessionRepository{ private static Logger logger = LoggerFactory.getLogger(JedisShiroSessionRepository.class); public static final String REDIS_SHIRO_SESSION = "shiro_redis_session:"; public static final String REDIS_SHIRO_ALL = "*shiro_redis_session:*"; public RedisManager getRedisManager() { return redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; } private RedisManager redisManager; @Override public void saveSession(Session session) { if(session == null || session.getId() == null){ logger.error("session or session id is null"); return; } session.setTimeout(redisManager.getExpire()* TimeEnum.SESSION_TIME_BASE.getCode()); getRedisManager().insertObject(this.buildRedisSessionKey(session.getId()), session, redisManager.getExpire()); } @Override public void deleteSession(Serializable sessionId) { if (sessionId == null) { throw new NullPointerException("session id is empty"); } getRedisManager().deleteObject(this.buildRedisSessionKey(sessionId)); } @Override public Session getSession(Serializable sessionId) { if (sessionId == null) throw new NullPointerException("session id is empty"); Session session = null; try { session =SerializeUtil.deserialize(getRedisManager().queryObjectByKey(this.buildRedisSessionKey(sessionId)),Session.class); } catch (Exception e) { logger.error( "获取session异常,id:[%s]",sessionId); } return session; } @Override public Collection<Session> getAllSessions() { Collection<Session> sessions = new HashSet<>();; try { Set<byte[]> byteKeys = getRedisManager().keys(REDIS_SHIRO_ALL); if (byteKeys != null && byteKeys.size() > 0) { for (byte[] bs : byteKeys) { Session obj =SerializeUtil.deserialize(getRedisManager().queryObjectByKey(bs),Session.class); if(obj instanceof Session){ sessions.add(obj); } } } } catch (Exception e) { logger.error(e.toString(),"获取全部session异常"); } return sessions; } private String buildRedisSessionKey(Serializable sessionId) { return REDIS_SHIRO_SESSION + sessionId; } }
RedisManager:
/** * Redis管理 * Created by Mac Zhang on 14-11-06 上午10:45 */ @Component public class RedisManager { protected org.slf4j.Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private StringRedisTemplate redisTemplate; /** * 查询redis数据库 * @param key 查询关键字 * @return redis 返回对象 ecustjxjy */ public byte[] queryObjectByKey(final Object key) { log.debug("queryObjectByKey request:{}", key); Object session =redisTemplate.execute(new RedisCallback<Object>() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { byte[] redisKey=null; if(key instanceof String) { redisKey = serialize(key); }else { redisKey=(byte[])key; } if (connection.exists(redisKey)) { return connection.get(redisKey); } return null; } }); return (byte[])session; } public Set<byte[]> keys(final String key){ log.debug("queryObjectByKey request:{}", key); Set<byte[]> value=redisTemplate.execute(new RedisCallback<Set<byte[]>>() { @Override public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException { byte[] redisKey = serialize(key); Set<byte[]> value = connection.keys(redisKey); return value; } }); return value; } /** * 插入redis 数据库,设置有效期 * @param obj 保存对象 * @param key 关键字 * @param timeout 有效期(秒) * @return 对象类型,泛型 */ public boolean insertObject(final String key,final Object obj,final long timeout){ log.debug("insertObject request:key={},obj={}", key, obj.getClass()); if(key.contains("SessionUser")){ System.out.println(SerializeUtil.deserialize((byte [])obj)); } boolean result = redisTemplate.execute(new RedisCallback<Boolean>() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { byte [] redisKey = serialize(key); byte [] redisValue = serialize(obj); connection.set(redisKey,redisValue); if(timeout > 0){ redisTemplate.expire(key, timeout, TimeUnit.SECONDS); } return true; } }); log.debug("insertObject response:{}", result); return result; } /** * 删除redis 保存对象 * @param key 查询关键字 * @return boolean */ public boolean deleteObject(final String key){ log.info("deleteObject request:key={}", key); Long result = redisTemplate.execute(new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { byte [] redisKey = seri ac4c alize(key); return connection.del(redisKey); } }); log.debug("deleteObject response:{}",result); return result > 0; } /** * 解决缓存key时前缀的乱码(序列化key时使用redis序列化) * @param key * @return */ public byte [] serialize(final Object key){ if(key instanceof String){ return this.redisTemplate.getStringSerializer().serialize(key.toString()); } return SerializeUtil.serialize(key); } public long getExpire(){ return TimeEnum.REDIS_EXPIRE_TIME.getCode(); } public Session deserialize(byte[] var1){ return SerializeUtil.deserialize(var1,Session.class); } }
通过上面的方式就可以实现session共享了,并且session由redis来保存。下一篇解决cache共享的问题。
相关文章推荐
- IT角色:足迹第八步给账号设定角色权限(如何使用Apache Shiro框架)
- springboot系列(二):Apache Shiro安全框架的简单使用
- 使用Apache shiro进行权限管理时如何对同一个URL配置多个角色的或关系
- apache shiro使用nginx集群如何解决cache共享
- 关于Apache Shiro权限框架的一些使用误区的解释
- 在Spring MVC中使用Apache Shiro安全框架
- Spring MVC 中Apache Shiro 框架的使用步骤
- 在Spring MVC中使用Apache Shiro安全框架
- 开发框架-Shiro-30分钟学会如何使用Shiro
- GlassFish中如何使用现有框架和技术
- Java安全框架Shiro的使用示例
- 通过分析蜘蛛侠论坛中的版块管理功能来介绍该如何使用我开发出来的ROM框架
- 如何在 Domino 上使用 Ajax 框架 Dojo
- 如何使用Apache作为前端负载均衡器(转自李其的文档)
- ADO.NET Entity Framework如何:使用存储过程定义模型(实体框架)
- ADO.NET Entity Framework 如何:自定义建模和映射文件以使用自定义对象(实体框架)
- ADO.NET Entity Framework 如何:使用存储过程定义模型(实体框架)
- 求助:如何使用VS的Profiler跟踪框架内部的方法调用?
- 网页设计中该如何决定是否使用框架技术
- [转]使用CPPUNIT如何建立一个基于MFC的GUI测试框架