shiro过滤器及会话管理
一.shiro过滤器
anon 不需要任何的认证就可以访问 user 当前存在用户才可以访问
authc 需要认证后才可以访问 logout 退出
authBasic (http认证? 说太快了 听不清啊)
和授权 相关的过滤器
perms[ ] 拥有某些权限才可以访问 roles[ ] 具有某些角色才可以访问
ssl 要求协议是什么 port 要求访问的端口号
二。会话管理将session交给redis管理
思路 重写sessionDao 在sessionDao中对session进行增删改查操作 ----redis
sessionDao
public class RedisSession extends AbstractSessionDAO { @Autowired private JedisUtil jedisUtil; private final String SHIRO_SESSION_PREFIX = "redis_session:"; private byte[] getKey (String key) { return (SHIRO_SESSION_PREFIX + key).getBytes(); } private void savaSession(Session session) { if (session != null && session.getId() != null) { byte[] key = getKey(session.getId().toString()); byte[] value = SerializationUtils.serialize(session); jedisUtil.set(key, value); jedisUtil.expire(key, 600); } } @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); savaSession(session); return sessionId; } @Override protected Session doReadSession(Serializable serializable) { System.out.println("read session"); if (serializable == null) { return null; } byte[] key = getKey(serializable.toString()); byte[] value = jedisUtil.get(key); return (Session) SerializationUtils.deserialize(value); } @Override public void update(Session session) throws UnknownSessionException { savaSession(session); } @Override public void delete(Session session) { if (session == null || session.getId() == null) { return; } byte[] key = getKey(session.getId().toString()); jedisUtil.del(key); } @Override public Collection<Session> getActiveSessions() { Set<byte[]> keys = jedisUtil.keys(SHIRO_SESSION_PREFIX); Set<Session> sessions = new HashSet<Session>(); if (CollectionUtils.isEmpty(keys)) { return sessions; } for (byte[] key : keys) { Session session = (Session) SerializationUtils.deserialize(jedisUtil.get(key)); sessions.add(session); } return sessions; } }
redis工具类
@Component public class JedisUtil{ @Autowired private JedisPool jedisPool; private Jedis getResource() { return jedisPool.getResource(); } public byte[] set(byte[] key, byte[] value) { Jedis jedis = getResource(); try { jedis.set(key, value); return value; } finally { jedis.close(); } } public void expire(byte[] key, int i) { Jedis jedis = getResource(); try { jedis.expire(key, i); } finally { jedis.close(); } } public byte[] get(byte[] key) { Jedis jedis = getResource(); try { return jedis.get(key); } finally { jedis.close(); } } public void del(byte[] key) { Jedis jedis = getResource(); try { jedis.del(key); } finally { jedis.close(); } } public Set<byte[]> keys(String shiro_session_prefix) { Jedis jedis = getResource(); try { return jedis.keys((shiro_session_prefix + "*").getBytes()); } finally { jedis.close(); } }
配置: sessionDao 给 sessionManager sessionManager给securityManager
<!--sessionManagger对象--> <bean class="com.zhuoshi.session.CustomSessionManager" name="defaultSessionManager"> <property name="sessionDAO" ref="sessionDao"/> </bean> <!--自定义的sessionDao--> <bean name="sessionDao" class="com.imooc.session.RedisSession"/> <!--创建securitymanager对象--> <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customRealm"/> <property name="sessionManager" ref="defaultSessionManager"/> </bean>
存在的问题: 多次读取redis中session数据 浪费系统资源:解决办法
源代码
可以看到每次调用sessionDao 中的read方法 造成读取次数过多 我们来重写这个方法 将session第一次读 取之后放在request中 之后读取从request中拿出session对象就可以完美的解决这问题。
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = getSessionId(sessionKey); if (sessionId == null) { log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " + "session could not be found.", sessionKey); return null; } Session s = retrieveSessionFromDataSource(sessionId); if (s == null) { //session ID was provided, meaning one is expected to be found, but we couldn't find one: String msg = "Could not find session with ID [" + sessionId + "]"; throw new UnknownSessionException(msg); } return s; }
protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException { return sessionDAO.readSession(sessionId); }
重写sessionManager 后的代码
@Override protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = getSessionId(sessionKey); ServletRequest request = null; if (sessionKey instanceof WebSessionKey) { request = ((WebSessionKey) sessionKey).getServletRequest(); } //判断request中是否有session 有的话从session中拿出session if (request != null && sessionId != null) { Session session = (Session) request.getAttribute(sessionId.toString()); if (session != null) { return session; } } //request 中没有session 从redis中读取session 然后放在request中 Session session = super.retrieveSession(sessionKey); if (request != null && sessionId != null) { request.setAttribute(sessionId.toString(), session); } return session; }
配置:当然要使用我们自定义的sessionManager
<!--sessionManagger对象--> <bean class="com.zhuoshi.session.CustomSessionManager" name="defaultSessionManager"> <property name="sessionDAO" ref="sessionDao"/> </bean>