• shiro缓存与session持久化


    今天给大家分享session缓存配置与session持久化示例

    1. shiro中的缓存

    在权限验证时每次从数据库中获取登陆权限数据显然是不合适的,更合适方式是将数据缓存到内存,以提高系统性能。

    1.1 引入jar包

    1.  
    2.        <dependency>
    3.            <groupId>org.apache.shirogroupId>
    4.            <artifactId>shiro-ehcacheartifactId>
    5.            <version>${shiro-version}version>
    6.        dependency>
    7.        <dependency>
    8.            <groupId>org.springframeworkgroupId>
    9.            <artifactId>spring-context-supportartifactId>
    10.            <version>${spring-version}version>
    11.        dependency>

    1.2 ehcache配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3.         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    4.         updateCheck="false">
    5.    <diskStore path="java.io.tmpdir"/>
    6.    
    7.    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
    8.                  timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    9.    
    10.  
    11. ehcache>

    1.2 配置spring-base的配置文件

    1. <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    2. <property name="configLocation" value="classpath:ehcache.xml"/>
    3. <property name="shared" value="true">property>
    4. bean>
    5. <bean id="shrioEhcache" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    6. <property name="cacheManager" ref="cacheManagerFactory">property>
    7. bean>
    8. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    9. <property name="realm" ref="shiroRealm" />
    10. <property name="cacheManager" ref="shrioEhcache">property>
    11. bean>

    2.shiro中的session

    2.1简单的小案例

    session中保存的数据,只要session未结束,在任何地方都可以访问session值

    必须要先登陆用户,使session里面有用户登陆的值,然后再访问session的值。

    mapper不用编写,因为咱们目的只是测试session获取值

    service层

     

    1. @Service
    2. public class SessionService implements ISession{
    3.    
    4.    @Override
    5.    public void Sessiontest() {
    6.        Session session = SecurityUtils.getSubject().getSession();
    7.        System.out.println("sesion is"+session.getAttribute("user"));
    8.   }
    9. }

     

    首先,登陆的Controller保存session的值,然后通过编写SessionController获取session的值

     

    1. @RequestMapping("user/login")
    2. public String login(User user, Model model, HttpSession session) {
    3.    Subject subject = SecurityUtils.getSubject();
    4.    UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword());
    5.    try {
    6.        subject.login(token);
    7.        session.setAttribute("user",user);
    8.   } catch (UnknownAccountException | LockedAccountException e) {
    9.        model.addAttribute("message", e.getMessage());
    10.        return "login";
    11.   } catch (AuthenticationException e) {
    12.        e.printStackTrace();
    13.        model.addAttribute("message", "密码错误");
    14.        return "login";
    15.   }
    16.    return "index";
    17. }

    编写一个简单SessionController得到session的值

    1. @Controller
    2. public class SessionController {
    3.    @Autowired
    4.    private ISession iSession;
    5.    @RequestMapping("Sessiontest")
    6.    public Object Sessiontest(){
    7.        iSession.Sessiontest();
    8.        return "";
    9.   }
    10. }

    效果展示

    3.Session监听

    效果展示 

    用于监听session的创建,过期等事件,如果在需要时可以再session创建时做些初始化操作,或在过期时做些清理操作。

    1) 创建一个自定义监听器

    1. @Slf4j//做为日志输出
    2. public class SessionListener extends SessionListenerAdapter {
    3.    @Override
    4.    public void onStart(Session session) {
    5.        log.info("Shiro session onStart .... ");
    6.   }
    7.    @Override
    8.    public void onStop(Session session) {
    9.        log.info("Shiro session onStop .... ");
    10.   }
    11.    @Override
    12.    public void onExpiration(Session session) {
    13.        log.info("Shiro session onExpiration ....");
    14.   }
    15. }

    2)配置文件,在spring配置文件中做如下配置

    1.  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    2.        <property name="realm" ref="shiroRealm" />
    3.        
    4.        <property name="cacheManager" ref="shrioEhcache"/>
    5.        
    6.        <property name="sessionManager" ref="sessionManager"/>
    7.    bean>
    8.    
    9.    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    10.        <property name="sessionListeners">
    11.            <list>
    12.                <bean class="com.zking.shirodemo.listener.SessionListener"/>
    13.            list>
    14.        property>
    15.    bean>

    4.session持久化

    登陆后

     

    由此可见,我们日志只打印了一个sql语句,说明只在数据库执行一次

     

    1)session持久化在applicationContext-base.xml配置文件

    1. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    2. <property name="sessionListeners">
    3. <list>
    4. <bean class="com.zking.spring.listener.SessionListener"/>
    5. list>
    6. property>
    7. <property name="sessionDAO" ref="sessionDao"/>
    8. bean>
    9. <bean id="sessionDao" class="com.zking.spring.listener.DbSessionDao">
    10. bean>

    2)将session持久化加入安全管理器

    1. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    2. <property name="realm" ref="shiroRealm" />
    3. <property name="cacheManager" ref="shrioEhcache">property>
    4. <property name="sessionManager" ref="sessionManager"/>
    5. bean>

    3)实现序列化接口,文章最后会附上序列化类

     

    4)因为session要写CRUD操作,mapper层service层就不显示了

    5)编写自定义的session,实现持久化必须要实现EnterpriseCacheSessionDAO接口,重写父类CRUD方法。

    1. /**
    2. * 自定义Session持久化,将Shiro的Session数据保存到数据库中。
    3. * 完成该类的编写后,需要在spring配置文件中进行配置
    4. */
    5. @Slf4j
    6. public class DbSessionDao extends EnterpriseCacheSessionDAO {
    7.    @Autowired
    8.    private ISessionModel sessionService;
    9.    @Override
    10.    protected Serializable doCreate(Session session) {
    11.        Serializable sid = super.doCreate(session);
    12.        SessionModel model = new SessionModel();
    13.        model.setSessionId(sid.toString());
    14.        model.setSession(SerializableUtil.serialize(session));
    15.        log.debug("将session保存到数据库, sessionId = {}", sid);
    16.        sessionService.addSession(model);
    17.        return sid;
    18.   }
    19.    @Override
    20.    protected Session doReadSession(Serializable sessionId) {
    21.        Session session = super.doReadSession(sessionId);
    22.        //如果从内存中获取了session,则直接返回
    23.        if (!Objects.isNull(session)) {
    24.            log.debug("从内存中获取session,sessionId = " + sessionId + ", 直接返回");
    25.            return session;
    26.       }
    27.        log.debug("从内存中没有获取到session,id={}, 将从数据库获取session", sessionId);
    28.        SessionModel model = new SessionModel();
    29.        model.setSessionId(sessionId.toString());
    30.        session  = (Session) sessionService.getSession(model);
    31.        if(Objects.isNull(session)) {
    32.            log.debug("数据库中也没有找到id={}的session,将返回null");
    33.       }
    34.        return session;
    35.   }
    36.    //删除session时,需要将数据表中的记录一并删除
    37.    @Override
    38.    protected void doDelete(Session session) {
    39.        SessionModel model = new SessionModel();
    40.        model.setSessionId(session.getId().toString());
    41.        log.debug("删除session,sessionId: " + session.getId().toString());
    42.        sessionService.delSession(model);
    43.        super.doDelete(session);
    44.   }
    45.    //更新session
    46.    @Override
    47.    protected void doUpdate(Session session) {
    48.        String sessionId = session.getId().toString();
    49.        SessionModel tmpModel = new SessionModel();
    50.        tmpModel.setSessionId(sessionId);
    51.        SessionModel model = sessionService.getSession(tmpModel);
    52.        if(Objects.isNull(model)) {
    53.            Object obj = session.getAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY);
    54.            //数据库中是否有session,如果没有检查session无效,则直接返回,否则保存到数据库中
    55.            if(Objects.isNull(obj) || !Boolean.parseBoolean(obj.toString())) {
    56.                return ;
    57.           }
    58.            SessionModel saveModel = new SessionModel();
    59.            saveModel.setSessionId(session.getId().toString());
    60.            saveModel.setSession(SerializableUtil.serialize(session));
    61.            log.debug("session已经过验证,且在数据库中不存在,将session保存到数据库 ..... ");
    62.            sessionService.addSession(saveModel);
    63.       } else {
    64.            //如果session在数据库中已存在,则更新session
    65.            model.setSession(SerializableUtil.serialize(session));
    66.            log.debug("session在数据库中已存在,将session更新到数据库 ..... ");
    67.            sessionService.updateSession(model);
    68.       }
    69.        //调用父类方法,更新session
    70.        super.doUpdate(session);
    71.   }
    72. }

    附1:序列化实现类

    1. public final class SerializableUtil {
    2.    private SerializableUtil() {}
    3.    /**
    4.     * Session序列化
    5.     * @param session 待序列化的session
    6.     * @return String
    7.     */
    8.    public static String serialize(Session session) {
    9.        try {
    10.            //ByteArrayOutputStream 用于存储序列化的Session对象
    11.            ByteArrayOutputStream bos = new ByteArrayOutputStream();
    12.            //将Object对象输出成byte数据
    13.            ObjectOutputStream out = new ObjectOutputStream(bos);
    14.            out.writeObject(session);
    15.            //将字节码,编码成String类型数据
    16.            return Base64.getEncoder().encodeToString(bos.toByteArray());
    17.       } catch (Exception e) {
    18.            e.printStackTrace();
    19.            throw new RuntimeException("序列化失败");
    20.       }
    21.   }
    22.    /**
    23.     * session的反向序列化
    24.     * @param sessionString 需要被反向序列化的对象
    25.     * @return
    26.     */
    27.    public static Session deserialize(String sessionString) {
    28.        try {
    29.            //读取字节码表
    30.            ByteArrayInputStream bis  = new ByteArrayInputStream(Base64.getDecoder().decode(sessionString));
    31.            //将字节码反序列化成 对象
    32.            ObjectInputStream in = new ObjectInputStream(bis);
    33.            Session session = (Session) in.readObject();
    34.            return session;
    35.       } catch (Exception e) {
    36.            throw new RuntimeException("反序列化失败");
    37.       }
    38.   }
    39. }

  • 相关阅读:
    11.ElasticSearch系列之搜索相关性算分机制
    智能算法之模拟退火算法
    文件系统考古 3:1994 - The SGI XFS Filesystem
    【C++】图片转byte
    Single-Shot Refinement Neural Network for Object Detection
    题目0100-找单词
    sql语句查询数据库字段和表字段数量
    【UVM基础】5、sequence、sequencer、item、driver
    将某路径下文件名批量获取填入表格中
    ReentrantLock锁与AQS的联系
  • 原文地址:https://blog.csdn.net/Bugxiu_fu/article/details/126816621