shiro session存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"
       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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hxpjava1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值