shiro session存redis

来源:互联网 发布:非结构化数据的处理 编辑:程序博客网 时间:2024/06/07 05:00

先看配置文件

<?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"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <description>Shiro安全配置</description><context:property-placeholder ignore-unresolvable="true" location="classpath:cookie.properties"/>            <!-- 安全认证过滤器 -->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager"/>        <property name="loginUrl" value="/common/login"/>        <property name="unauthorizedUrl" value="/error/403"/>        <property name="successUrl" value="/admins/indexed/index"></property>        <property name="filters">            <map>                <entry key="exec">                    <bean class="com.mark.demo.shiro.security.filter.SimpleExecutiveFilter"/>                </entry>                <entry key="authc">                    <bean class="com.mark.demo.shiro.security.filter.AuthenticationFilter">                        <property name="rememberMeParam" value="rememberMe"/>                    </bean>                </entry>                <entry key="roles">                    <bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"/>                </entry>            </map>        </property>        <property name="filterChainDefinitions">            <value>                /js/** = anon,exec                /css/** = anon,exec                /video/** = anon,exec                /upload/** = anon,exec                /uploads/** = anon,exec                /fonts/** = anon,exec                /getAuthPrice/** = anon,exec                /common/login/** = anon,exec                /common/forgotpass/** = anon,exec                /menu/** = authc,exec                /brand/** = authc,exec                /common/** = authc,exec                /admins/** = authc,exec            </value>        </property>    </bean>    <!-- 定义授权缓存管理器 -->    <bean id="shiroCacheManager" class="com.mark.demo.shiro.security.cache.RedisCacheManager"/>    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>    <!-- SHIRO 认证匹配 -->    <bean id="userCredentialsMatcher" class="com.mark.demo.shiro.security.UserCredentialsMatcher"/>    <!-- 系统安全认证 -->    <bean id="userAuthorizingRealm" class="com.mark.demo.shiro.security.MysqlRealm">        <property name="credentialsMatcher" ref="userCredentialsMatcher"/>        <property name="sessionDAO" ref="sessionDAO"/>        <property name="userMapper" ref="userMapper"></property>    </bean>    <!-- 自定义会话 -->    <bean id="sessionDAO" class="com.mark.demo.shiro.security.session.RedisSessionDAO">        <property name="sessionIdGenerator">            <bean class="com.mark.demo.shiro.security.utils.IdGen"/>        </property>    </bean>    <!-- 指定本系统SESSIONID, 默认为: JSESSIONID -->    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">        <constructor-arg name="name" value="${cookie.session}"/>        <property name="domain" value="${cookie.domain}"/>        <property name="path" value="${cookie.path}"/>        <property name="httpOnly" value="true"/>    </bean>    <!-- 指定本系统REMEMBERID -->    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">        <constructor-arg name="name" value="${cookie.remember}"/>        <property name="domain" value="${cookie.domain}"/>        <property name="path" value="${cookie.path}"/>        <property name="httpOnly" value="true"/>        <property name="maxAge" value="2592000"/>    </bean>    <!-- 自定义会话管理配置 -->    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">        <property name="sessionDAO" ref="sessionDAO"/>        <property name="globalSessionTimeout" value="1800000"/>        <property name="sessionValidationInterval" value="120000"/>        <property name="sessionValidationSchedulerEnabled" value="true"/>        <property name="sessionIdCookie" ref="sessionIdCookie"/>        <property name="sessionIdCookieEnabled" value="true"/>    </bean>    <!-- rememberMe管理器 -->    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>        <property name="cookie" ref="rememberMeCookie"/>    </bean>    <!-- 定义Shiro安全管理配置 -->    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <property name="realm" ref="userAuthorizingRealm"/>        <property name="rememberMeManager" ref="rememberMeManager"/>        <property name="sessionManager" ref="sessionManager"/>        <property name="cacheManager" ref="shiroCacheManager"/>        <property name="sessionMode" value="http"></property>    </bean>    <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>        <property name="arguments" ref="securityManager"/>    </bean></beans>

主要就是实现
com.mark.demo.shiro.security.session.RedisSessionDAO

当session有更新时就会使用这个dao更新redis里的缓存

package com.mark.demo.shiro.security.session;import java.util.Collection;import org.apache.shiro.session.Session;public interface CustomSessionDAO extends org.apache.shiro.session.mgt.eis.SessionDAO{    /**     * 获取活动会话     * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)     * @return     */    Collection<Session> getActiveSessions(boolean includeLeave);        /**     * 获取活动会话     * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)     * @param principal 根据登录者对象获取活动会话     * @param filterSession 不为空,则过滤掉(不包含)这个会话。     * @return     */    Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession);}

package com.mark.demo.shiro.security.session;import java.io.Serializable;import java.util.Collection;import java.util.Date;import java.util.Map;import java.util.Set;import org.apache.shiro.SecurityUtils;import org.apache.shiro.session.Session;import org.apache.shiro.session.UnknownSessionException;import org.apache.shiro.session.mgt.SimpleSession;import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;import org.apache.shiro.subject.SimplePrincipalCollection;import org.apache.shiro.subject.support.DefaultSubjectContext;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.google.common.collect.Sets;import com.mark.demo.shiro.entity.User;import com.mark.demo.shiro.utils.JedisUtils;import com.mark.demo.shiro.utils.StringUtils;public class RedisSessionDAO extends AbstractSessionDAO implements CustomSessionDAO{    private static final Logger logger         = LoggerFactory.getLogger(RedisSessionDAO.class);        public static final String  SESSION_GROUPS = "redis_shiro_session_group";        public static final String  SESSION_PREFIX = "session_";        @Override    public void update(Session session) throws UnknownSessionException    {        if (session == null || session.getId() == null) { return; }        String key = String.valueOf(SESSION_PREFIX + session.getId());        int timeoutSeconds = (int) (session.getTimeout() / 1000);        JedisUtils.setObject(key, session, timeoutSeconds);        User principal = null;        SimplePrincipalCollection collection = (SimplePrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);        if (null != collection)        {            principal = (User) collection.getPrimaryPrincipal();        }                    String principalId = principal != null ? principal.getId()+"": StringUtils.EMPTY;        JedisUtils.setMapField(SESSION_GROUPS, key, principalId + "|" + session.getTimeout() + "|" + session.getLastAccessTime().getTime());            }        /**     * 清空会话及缓存     */    public static void clean()    {    Map<String, String> map=JedisUtils.getMap(SESSION_GROUPS);    JedisUtils.del(SESSION_GROUPS);    for (Map.Entry<String, String> entry : map.entrySet())        {            JedisUtils.del(entry.getKey());            if (logger.isDebugEnabled())            {                logger.debug("remove session {} ", entry.getKey());            }        }        }        @Override    public void delete(Session session)    {        if (session == null || session.getId() == null) { return; }        String key = String.valueOf(SESSION_PREFIX + session.getId());        JedisUtils.removeMapField(SESSION_GROUPS,key);        JedisUtils.del(key);            }        @Override    public Collection<Session> getActiveSessions()    {        return getActiveSessions(true);    }        /**     * 获取活动会话     * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)     * @return     */    @Override    public Collection<Session> getActiveSessions(boolean includeLeave)    {        return getActiveSessions(includeLeave, null, null);    }        /**     * 获取活动会话     * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)     * @param principal 根据登录者对象获取活动会话     * @param filterSession 不为空,则过滤掉(不包含)这个会话。     * @return     */    @Override    public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession)    {        Set<Session> sessions = Sets.newHashSet();        try        {            Map<String, String> map =JedisUtils.getMap(SESSION_GROUPS);            if(map==null){            return sessions;            }            for (Map.Entry<String, String> e : map.entrySet())            {                if (StringUtils.isNotBlank(e.getKey()) && StringUtils.isNotBlank(e.getValue()))                {                    String[] ss = StringUtils.split(e.getValue(), "|");                    if (ss != null && ss.length == 3)                    {                        SimpleSession session = new SimpleSession();                        session.setId(e.getKey());                        session.setAttribute("principalId", ss[0]);                        session.setTimeout(Long.valueOf(ss[1]));                        session.setLastAccessTime(new Date(Long.valueOf(ss[2])));                        try                        {                            // 验证SESSION                            session.validate();                            boolean isActiveSession = false;                            // 不包括离线并符合最后访问时间小于等于3分钟条件。                            if (includeLeave )                            {                                isActiveSession = true;                            }                            // 过滤掉的SESSION                            if (filterSession != null && filterSession.getId().equals(session.getId()))                            {                                isActiveSession = false;                            }                            if (isActiveSession)                            {                                sessions.add(session);                            }                        }                        // SESSION验证失败                        catch (Exception e2)                        {                        JedisUtils.removeMapField(SESSION_GROUPS, e.getKey());                        JedisUtils.del(e.getKey());                        }                    }                    // 存储的SESSION不符合规则                    else                    {                    JedisUtils.removeMapField(SESSION_GROUPS, e.getKey());                    JedisUtils.del(e.getKey());                    }                }                // 存储的SESSION无Value                else if (StringUtils.isNotBlank(e.getKey()))                {                JedisUtils.removeMapField(SESSION_GROUPS, e.getKey());                JedisUtils.del(e.getKey());                }            }            logger.info("getActiveSessions size: {} ", sessions.size());        }        catch (Exception e)        {            logger.error("getActiveSessions", e);        }                return sessions;    }        @Override    protected Serializable doCreate(Session session)    {        Serializable sessionId = this.generateSessionId(session);        this.assignSessionId(session, sessionId);        this.update(session);       // SecurityUtils.getSubject()        return sessionId;    }        @Override    protected Session doReadSession(Serializable sessionId)    {        Session session = null;        try        {            String key = String.valueOf(SESSION_PREFIX + sessionId);            session = (Session) JedisUtils.getObject(key);        }        catch (Exception e)        {            logger.error("doReadSession {} {}", sessionId, e);        }                return session;    }        @Override    public Session readSession(Serializable sessionId) throws UnknownSessionException    {        try        {            return super.readSession(sessionId);        }        catch (UnknownSessionException e)        {            return null;        }    }}
demo地址:https://github.com/13567436138/shiro-demo