欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot整合redis实现shiro的分布式session共享的方法

程序员文章站 2023-11-24 09:09:52
我们知道,shiro是通过sessionmanager来管理session的,而对于session的操作则是通过sessiondao来实现的,默认的情况下,shiro实现了...

我们知道,shiro是通过sessionmanager来管理session的,而对于session的操作则是通过sessiondao来实现的,默认的情况下,shiro实现了两种sessiondao,分别为cachingsessiondao和memorysessiondao,当我们使用ehcache缓存时,则是使用的cachingsessiondao,不适用缓存的情况下,就会选择基于内存的sessiondao.所以,如果我们想实现基于redis的分布式session共享,重点在于重写sessionmanager中的sessiondao。我们的重写代码如下:

package com.chhliu.springboot.shiro.cache; 
import java.io.serializable; 
import java.util.collection; 
import java.util.concurrent.timeunit; 
import org.apache.shiro.session.session; 
import org.apache.shiro.session.unknownsessionexception; 
import org.apache.shiro.session.mgt.eis.abstractsessiondao; 
import org.springframework.beans.factory.annotation.autowired; 
import org.springframework.data.redis.core.redistemplate; 
import org.springframework.stereotype.service;  
@service 
@suppresswarnings({ "rawtypes", "unchecked" }) 
public class redissessiondao extends abstractsessiondao { 
 
  // session超时时间,单位为毫秒 
  private long expiretime = 120000; 
 
  @autowired 
  private redistemplate redistemplate;// redis操作类,对这个使用不熟悉的,可以参考前面的博客 
 
  public redissessiondao() { 
    super(); 
  } 
 
  public redissessiondao(long expiretime, redistemplate redistemplate) { 
    super(); 
    this.expiretime = expiretime; 
    this.redistemplate = redistemplate; 
  } 
 
  @override // 更新session 
  public void update(session session) throws unknownsessionexception { 
    system.out.println("===============update================"); 
    if (session == null || session.getid() == null) { 
      return; 
    } 
    session.settimeout(expiretime); 
    redistemplate.opsforvalue().set(session.getid(), session, expiretime, timeunit.milliseconds); 
  } 
 
  @override // 删除session 
  public void delete(session session) { 
    system.out.println("===============delete================"); 
    if (null == session) { 
      return; 
    } 
    redistemplate.opsforvalue().getoperations().delete(session.getid()); 
  } 
 
  @override// 获取活跃的session,可以用来统计在线人数,如果要实现这个功能,可以在将session加入redis时指定一个session前缀,统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合 
  public collection<session> getactivesessions() { 
    system.out.println("==============getactivesessions================="); 
    return redistemplate.keys("*"); 
  } 
 
  @override// 加入session 
  protected serializable docreate(session session) { 
    system.out.println("===============docreate================"); 
    serializable sessionid = this.generatesessionid(session); 
    this.assignsessionid(session, sessionid); 
 
    redistemplate.opsforvalue().set(session.getid(), session, expiretime, timeunit.milliseconds); 
    return sessionid; 
  } 
 
  @override// 读取session 
  protected session doreadsession(serializable sessionid) { 
    system.out.println("==============doreadsession================="); 
    if (sessionid == null) { 
      return null; 
    } 
    return (session) redistemplate.opsforvalue().get(sessionid); 
  } 
 
  public long getexpiretime() { 
    return expiretime; 
  } 
 
  public void setexpiretime(long expiretime) { 
    this.expiretime = expiretime; 
  } 
 
  public redistemplate getredistemplate() { 
    return redistemplate; 
  } 
 
  public void setredistemplate(redistemplate redistemplate) { 
    this.redistemplate = redistemplate; 
  } 
} 

sessiondao实现完了之后,我们就需要将sessiondao加入sessionmanager中了,代码如下:

 @bean 
  public defaultwebsessionmanager configwebsessionmanager(){ 
    defaultwebsessionmanager manager = new defaultwebsessionmanager(); 
    manager.setcachemanager(cachemanager);// 加入缓存管理器 
    manager.setsessiondao(sessiondao);// 设置sessiondao 
    manager.setdeleteinvalidsessions(true);// 删除过期的session 
    manager.setglobalsessiontimeout(sessiondao.getexpiretime());// 设置全局session超时时间 
    manager.setsessionvalidationschedulerenabled(true);// 是否定时检查session 
     
    return manager; 
  } 

最后一步就是将sessionmanager配置到securitymanager中了

@bean 
  public securitymanager securitymanager(defaultwebsessionmanager websessionmanager) { 
    defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager(); 
    // 设置realm. 
    securitymanager.setrealm(myshirorealm()); 
 
    // 注入缓存管理器; 
    securitymanager.setcachemanager(cachemanager);// 这个如果执行多次,也是同样的一个对象; 
     
    // session管理器 
    securitymanager.setsessionmanager(websessionmanager); 
     
    //注入记住我管理器; 
    securitymanager.setremembermemanager(remembermemanager()); 
    return securitymanager; 
  } 

测试结果如下:

==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
===============update================ 
==============doreadsession================= 
==============doreadsession================= 
===============update================ 
==============doreadsession================= 
==============doreadsession================= 
==============doreadsession================= 
权限配置-->myshirorealm.dogetauthorizationinfo() 
==============doreadsession================= 

我们会发现,当一个页面中存在多个资源的时候,会不停的调用doreadsession,update方法来读取和更新session,目前这个问题还没有想到比较好的解决方案。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。