shiro使用reids缓存session 踩坑 (已解决)

shiro使用reids缓存session 踩坑

方案一: shiro-redis插件[未成功]

方案二: 修改sessionDao,手动实现存储读取 [成功]

shiro配置

@Configuration
public class ShiroConfig {
    
    

    @Value("${spring.redis.shiro.host}")
    private String host;
    @Value("${spring.redis.shiro.port}")
    private int port;
    @Value("${spring.redis.shiro.timeout}")
    private int timeout;
    @Value("${spring.redis.shiro.password}")
    private String password;

	// 这个redisUtil是json格式的存储读取
    @Resource
    RedisUtil redisUtil;
    // 这个是btye格式的存储和读取,由于session格式成json一直报序列化错误,只能存成byte
    @Resource
    RedisSessionUtil redisSessionUtil;

    @Value(value = "${mcinema.auth.session-token-key}")
    private String SESSION_TOKEN_KEY;
    @Value(value = "${mcinema.redis-key.session-admin}")
    private String sessionRoot;

    // 注册shiroFilterFactoryBean
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
    
    
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        Map<String, String> filter = new LinkedHashMap<>();
        // 设置拦截器
        bean.setFilterChainDefinitionMap(filter);
        return bean;
    }
     //注册DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager adminWebSecurityManager(
            AdminRealm adminRealm,
            AdminSessionManagement sessionManager) {
    
    
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(adminRealm); // 设置Realm对象
        securityManager.setSessionManager(sessionManager); // 设置session管理
        return securityManager;
    }

  	//注册Realm
    @Bean(name = "adminRealm")
    public AdminRealm adminRealm() {
    
    
        return new AdminRealm();
    }

    // 注册sessionManager
    @Bean(name = "sessionManager")
    public AdminSessionManagement adminSessionManagement(AdminSessionDAO adminSessionDAO) {
    
    
        AdminSessionManagement sessionManagement = new AdminSessionManagement(SESSION_TOKEN_KEY);
        sessionManagement.setSessionDAO(adminSessionDAO);
        return sessionManagement;
    }

    @Bean(name="adminSessionDAO")
    public AdminSessionDAO adminSessionDAO(){
    
    
        return new AdminSessionDAO(redisSessionUtil,sessionRoot);
    }
    

    // 开启注解功能
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    
    
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    
    
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

redis template配置

    @Bean(name = "redisSessionTemplate")
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisSessionTemplate(RedisConnectionFactory factory) {
    
    
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);

        MyRedisSerializer myRedisSerializer = new MyRedisSerializer();

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(myRedisSerializer);
        template.setHashValueSerializer(myRedisSerializer);
        template.setDefaultSerializer(myRedisSerializer);
        template.afterPropertiesSet();

        return template;
    }

自定义序列化方式 这个更shiro-redis插件配置的ObjectSerialize差不多,不知道为什么我用那个还是会报错

public class MyRedisSerializer implements RedisSerializer<Object> {
    
    
 
 
    @Override
    public byte[] serialize(Object o) throws SerializationException {
    
    
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut;
        try {
    
    
            objOut = new ObjectOutputStream(byteOut);
            objOut.writeObject(o);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return byteOut.toByteArray();
    }
 
    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
    
    
        if(bytes == null) return null;
        ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
        ObjectInputStream objIn;
        Object obj;
        try {
    
    
            objIn = new ObjectInputStream(byteIn);
            obj =objIn.readObject();
        } catch (IOException | ClassNotFoundException e) {
    
    
            e.printStackTrace();
            return null;
        }
        return obj;
    }
 
}

redisUtil就不贴了,都差不多,你改下操作的template就行了

看运行发现读取次数过多,网上的办法是将获取的session存储到request里
自定义的sessionManager 继承 defaultSessionManage 覆写 retrieveSession方法

这个是网上抄的,水平有限,就没改了,能用就行,发现问题评论告诉我

public class AdminSessionManagement extends DefaultWebSessionManager{
    
    
    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
    
    
        Serializable sessionId = getSessionId(sessionKey);
        if (sessionId == null) {
    
    
            log.debug("Unable to resolve session ID from SessionKey [{}].  Returning null to indicate a "
                    + "session could not be found.", sessionKey);
            return null;
        }
        // ***************Add By Goma****************
        ServletRequest request = null;
        if (sessionKey instanceof WebSessionKey) {
    
    
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }

        if (request != null) {
    
    
            Object s = request.getAttribute(sessionId.toString());
            if (s != null) {
    
    
                return (Session) s;
            }
        }
        // ***************Add By Goma****************

        Session s = retrieveSessionFromDataSource(sessionId);
        if (s == null) {
    
    
            // session ID was provided, meaning one is expected to be found, but
            // we couldn't find one:
            String msg = "Could not find session with ID [" + sessionId + "]";
            throw new UnknownSessionException(msg);
        }
        // ***************Add By Goma****************
        if (request != null) {
    
    
            request.setAttribute(sessionId.toString(), s);
        }
        // ***************Add By Goma****************
        return s;
    }
	// session的键值
    private final String SESSION_TOKEN_KEY;
    // session的来源
    private static final String SESSION_SOURCE = "request header";

    public AdminSessionManagement(String session_token_key) {
    
    
        this.SESSION_TOKEN_KEY = session_token_key;
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
    
    
        String id = WebUtils.toHttp(request).getHeader(SESSION_TOKEN_KEY);
        if (DataUtil.checkEmpty(id)) {
    
    
            WebUtils.toHttp(response).setHeader(SESSION_TOKEN_KEY, id);
            // 设置session来源
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, SESSION_SOURCE);
            // 设置sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            // 设置标记此sessionId为有效
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        }
        return super.getSessionId(request, response);
    }
}

猜你喜欢

转载自blog.csdn.net/reol44/article/details/129650540
今日推荐