shiro-会话管理(session管理)

本文介绍了如何使用Apache Shiro框架结合Redis来实现会话管理,包括自定义SessionDAO实现Session的CRUD操作,通过Jedis工具类与Redis交互,以及配置Spring以使用RedisSessionDao。同时,为了避免DefaultWebSessionManager的资源浪费,创建了CustomSessionManager来优化session的检索过程。

shiro-会话管理(session管理)

shiro自己实现了一套session管理体系可以在不借助任何web容器或servlet的情况下使用session。
1.SessionManager(session管理器)、SessionDAO(实现session的增删改查)
2.Redis实现Session共享
3.Redis实现Session共享存在的问题
代码:
pom.xml文件中添加依赖

    <dependency>
                <groupId>redis.client</groupId>
                <artifactId>jedis</artifactId>
                <version>2.8.0</version>
    </dependency>

通过jedis来实现session共享主要是重写他的一些增删改查方法,主要是通过重写AbstractSessionDAO的一些方法,我们新建自己的dao,新建session.RedisSessionDao.java。

package com.imooc.session;

import com.imooc.Util.JedisUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.util.SerializationUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class RedisSessionDao extends AbstractSessionDAO{

    @Resource
    private JedisUtil jedisUtil;

    private final  String SHIRO_SESSION_PREFIX = "imooc_session";

    /*key由sessionid和前缀SHIRO_SESSION_PREFIX组成 二进制方式返回*/
    private byte[] getKey(String key){
        return (SHIRO_SESSION_PREFIX+key).getBytes();
    }

    /*保存session*/
    private void saveSession(Session session){
        if (session!=null&&session.getId()!=null){
            byte[] key = getKey(session.getId().toString());
            /*将session序列化*/
            byte[] value = SerializationUtils.serialize(session);
            jedisUtil.set(key,value);
            /*设置超时时间*/
            jedisUtil.expire(key,600);
        }

    }

    @Override
    protected Serializable doCreate(Session session) {
        /*通过sessionId保存对应的session*/
        Serializable sessionId = generateSessionId(session);
        /*将sessionId和session捆绑*/
        assignSessionId(session,sessionId);
       saveSession(session);
        return sessionId;
    }

    /**
     * 通过sessionId获得session
     * @param sessionId
     * @return
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId==null){
            return null;
        }
        byte[] key = getKey(sessionId.toString());
        byte[] value = jedisUtil.get(key);
        //将值反序列化为session对象
        return (Session) SerializationUtils.deserialize(value);
    }

    public void update(Session session) throws UnknownSessionException {
       saveSession(session);

    }

    public void delete(Session session) {

        if(session==null||session.getId()==null){
            return;
        }
        byte[] key = getKey(session.getId().toString());
        jedisUtil.del(key);
    }

    /*获得指定的存活的session*/
    public Collection<Session> getActiveSessions() {
        /*通过前缀获得相关的所有的key*/
        Set<byte[]> keys = jedisUtil.getKeys(SHIRO_SESSION_PREFIX);
        Set<Session> sessions = new HashSet<Session>();
        if (CollectionUtils.isEmpty(keys)){
            return sessions;
        }
        for(byte[] key: keys){
            //反序列化为session对象
            Session session = (Session) SerializationUtils.deserialize(jedisUtil.get(key));
            sessions.add(session);
        }

        return sessions;
    }
}

创建一个Redis访问的工具包,新建utils.JedisUtil.java

package com.imooc.Util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Set;


/**
 * 写Jedis操作的一些方法
 */
@Component
public class JedisUtil {

    /**
     * JedisPool连接池,用于获取连接
     */
   @Autowired
   private JedisPool jedisPool;

    private Jedis getResources(){
        return jedisPool.getResource();
    }


    public byte[] set(byte[] key, byte[] value) {

        Jedis jedis = jedisPool.getResource();
        try{
            jedis.set(key,value);
            return value;
        }finally {
            jedis.close();
        }

    }

    /*设置指定key的超时时间,单位为s*/
    public void expire(byte[] key, int i) {
        Jedis jedis = jedisPool.getResource();
        try{
            jedis.expire(key,i);
        }finally {
            jedis.close();
        }
    }

    public byte[] get(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try{
            return jedis.get(key);
        }finally {
            jedis.close();
        }
    }

    public void del(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try{
            jedis.del(key);
        }finally {
            jedis.close();
        }
    }

    public Set<byte[]> getKeys(String shiro_session_prefix) {
        Jedis jedis = jedisPool.getResource();
        try{
            return jedis.keys((shiro_session_prefix+"*").getBytes());
        }finally {
            jedis.close();
        }
    }
}

```创建Redis相关的spring文件,通过构造器的方式来创建。
spring-redis.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="redis.clients.jedis.JedisPool" id="JedisPool">
        <constructor-arg ref="JedisPoolConfig"/>
        <constructor-arg value="127.0.0.1"/>
        <constructor-arg value="6379"/>
    </bean>

    <bean class="redis.clients.jedis.JedisPoolConfig" id="JedisPoolConfig"/>

</beans>

这样我们的JedisPool就创建成功了,我们在JedisUtils里引入。
在spring.xml文件里引入spring-redis.xml。

<import resource="spring-redis.xml"/>

将JedisUtil注入RedisSessionDao中,

@Resource
    private JedisUtil jedisUtil;

小记:注入就是spring的管理机制bean工厂已经把对象及其属性创建好,只需要程序员去调用。关于spring注入的方式,引用一下一位大佬的博客。https://blog.youkuaiyun.com/a909301740/article/details/78379720

RedisSessionDao重写AbstractSessionDao的详细方法我们卸载JedisUtils里。
++++++我是分割线----进入第二部分啦+++
在spring.xml里配置sessionManager

<bean class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager" id="sessionManager">
        <property name="sessionDAO" ref="redisSessionDao"/>
    </bean>

    <bean class="com.imooc.session.RedisSessionDao" id="redisSessionDao"/>

在securityManager中加入sessionManager属性

<property name="sessionManager" ref="sessionManager"/>

因为DefaultWebSessionManager会重复多次读取session浪费资源,所以我们重写一下DefaultWebSessionManager的retrieveSession方法
CustomSessionManager.java

package com.imooc.session;

import com.sun.xml.internal.ws.developer.Serialization;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.omg.CORBA.ServerRequest;

import javax.servlet.ServletRequest;
import java.io.Serializable;

public class CustomSessionManager extends DefaultWebSessionManager{

    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        Serializable sessionId = getSessionId(sessionKey);
        ServletRequest request = null;
        if (sessionKey instanceof WebSessionKey){
            request = (ServletRequest) ((WebSessionKey) sessionKey).getServletRequest();
        }
        if (request!=null&&sessionId!=null) {
            Session session = (Session) request.getAttribute(sessionId.toString());
            if(session!=null)
            {
                return session;
            }
        }
       Session session = super.retrieveSession(sessionKey);
        if(request!=null &&sessionId!=null){
            request.setAttribute(sessionId.toString(),session);
        }
        return session;
    }
}
Shiro-Redis 是一个用于在 Shiro 中实现 Session 共享的插件,它使用 Redis 作为数据存储和缓存,以实现分布式环境下的 Session 共享。 要实现 Shiro-RedisSession 共享,你需要进行以下步骤: 1. 引入 Shiro-Redis 插件依赖:在项目的 Maven 或 Gradle 配置文件中添加 Shiro-Redis 依赖。 2. 配置 Redis 连接信息:在项目的配置文件中配置 Redis 的连接信息,包括主机名、端口号、密码等。 3. 配置 RedisSessionDAO:在 Shiro 的配置文件中配置 RedisSessionDAO,指定使用 Redis 作为 Session 存储和缓存的实现。可以设置过期时间、前缀等参数。 4. 配置 Session Manager:在 Shiro 的配置文件中配置 Session Manager,指定使用自定义的 RedisSessionManager 作为 Session管理器。同时,需要将之前配置的 RedisSessionDAO 设置给 RedisSessionManager。 5. 配置 SecurityManager:在 Shiro 的配置文件中配置 SecurityManager,指定使用自定义的 RedisSessionManager 作为 Session 管理器。同时,需要将之前配置的 RedisSessionDAO 设置给 RedisSessionManager。 6. 配置 Filter Chain:在 Shiro 的配置文件中配置 Filter Chain,将自定义的 RedisSessionManager 添加到 Filter Chain 中,以便对请求进行 Session 管理。 通过以上步骤配置完成后,Shiro 将会使用 Redis 进行 Session 的存储和缓存,从而实现 Session 的共享。在分布式环境中,不同应用节点之间可以通过 Redis 共享 Session 数据,从而实现用户的登录状态和会话信息的共享。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值