shiro原理_java:shiro高级篇——1

第六章 Realm缓存机制

1、Realm缓存机制意义

在上面我们自定了自己的realm,但是我们发现

d0ffe1e44e2f58ea916a3b831b7e2a88.png

在认证和授权的时候,程序需要频繁的访问数据库,这样对于数据库的压力可想而知,那我们怎么处理呢?

2、Realm缓存机制实现思路

【1】缓存机制图解

68e8fc56fff00d9a877d2d3d25869847.png

【2】原理分析

此时我们对UserBridgeServiceImpl的实现类里面的逻辑加入了自定义的SimpleCacheService缓存服务接口,简单来说实现了在认证和鉴权时不需要每次都去查询数据库,而是把认证和鉴权信息放入到redis缓存中,以减低数据库的访问压力

1、集成redis服务器,作为集中存储认证和鉴权信息 2、改写UserBridgeServiceImpl使其优先从缓存中读取

3、redission集成

【1】添加ShiroRedisProperties

此类主要负责yaml文件的配置类

package com.itheima.shiro.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import java.io.Serializable;/** * @Description  redis配置文件 */@Data@ConfigurationProperties(prefix = "itheima.framework.shiro.redis")public class ShiroRedisProperties implements Serializable {    /**     * redis连接地址     */    private String nodes ;    /**     * 获取连接超时时间     */    private int connectTimeout ;    /**     * 连接池大小     */    private int connectPoolSize;    /**     * 初始化连接数     */    private int connectionMinimumidleSize ;    /**     * 等待数据返回超时时间     */    private int timeout ;    /**     *  全局超时时间     */    private long globalSessionTimeout;}

【2】编辑ShiroConfig

集成redisson的相关配置,同时启用ShiroRedisProperties的配置

package com.itheima.shiro.config;import com.itheima.shiro.core.ShiroDbRealm;import com.itheima.shiro.core.impl.ShiroDbRealmImpl;import com.itheima.shiro.filter.RolesOrAuthorizationFilter;import com.itheima.shiro.properties.PropertiesUtil;import lombok.extern.log4j.Log4j2;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.apache.shiro.web.servlet.SimpleCookie;import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;/** * @Description 权限配置类 */@Configuration@ComponentScan(basePackages = "com.itheima.shiro.core")@EnableConfigurationProperties({ShiroRedisProperties.class})@Log4j2public class ShiroConfig {    @Autowired    private ShiroRedisProperties shiroRedisProperties;    /**     * @Description redission客户端     */    @Bean("redissonClientForShiro")    public RedissonClient redissonClient() {        log.info("=====初始化redissonClientForShiro开始======");        String[] nodeList = shiroRedisProperties.getNodes().split(",");        Config config = new Config();        if (nodeList.length == 1) {            config.useSingleServer().setAddress(nodeList[0])                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());        } else {            config.useClusterServers().addNodeAddress(nodeList)                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());        }        RedissonClient redissonClient =  Redisson.create(config);        log.info("=====初始化redissonClientForShiro完成======");        return redissonClient;    }    /**     * @Description 创建cookie对象     */    @Bean(name="sessionIdCookie")    public SimpleCookie simpleCookie(){        SimpleCookie simpleCookie = new SimpleCookie();        simpleCookie.setName("ShiroSession");        return simpleCookie;    }    /**     * @Description 权限管理器     * @param     * @return     */    @Bean(name="securityManager")    public DefaultWebSecurityManager defaultWebSecurityManager(){        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        securityManager.setRealm(shiroDbRealm());        securityManager.setSessionManager(shiroSessionManager());        return securityManager;    }    /**     * @Description 自定义RealmImpl     */    @Bean(name="shiroDbRealm")    public ShiroDbRealm shiroDbRealm(){        return new ShiroDbRealmImpl();    }    /**     * @Description 会话管理器     */    @Bean(name="sessionManager")    public DefaultWebSessionManager shiroSessionManager(){        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();        sessionManager.setSessionValidationSchedulerEnabled(false);        sessionManager.setSessionIdCookieEnabled(true);        sessionManager.setSessionIdCookie(simpleCookie());        sessionManager.setGlobalSessionTimeout(3600000);        return sessionManager;    }    /**     * @Description 保证实现了Shiro内部lifecycle函数的bean执行     */    @Bean(name = "lifecycleBeanPostProcessor")    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {        return new LifecycleBeanPostProcessor();    }    /**     * @Description AOP式方法级权限检查     */    @Bean    @DependsOn("lifecycleBeanPostProcessor")    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);        return defaultAdvisorAutoProxyCreator;    }    /**     * @Description 配合DefaultAdvisorAutoProxyCreator事项注解权限校验     */    @Bean    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();        aasa.setSecurityManager(defaultWebSecurityManager());        return new AuthorizationAttributeSourceAdvisor();    }    /**     * @Description 过滤器链     */    private Map filterChainDefinition(){        List list  = PropertiesUtil.propertiesShiro.getKeyList();        Map map = new LinkedHashMap<>();        for (Object object : list) {            String key = object.toString();            String value = PropertiesUtil.getShiroValue(key);            log.info("读取防止盗链控制:---key{},---value:{}",key,value);            map.put(key, value);        }        return map;    }    /**     * @Description 自定义过滤器定义     */    private Map filters() {        Map map = new HashMap();        map.put("roleOr", new RolesOrAuthorizationFilter());        return map;    }    /**     * @Description Shiro过滤器     */    @Bean("shiroFilter")    public ShiroFilterFactoryBean shiroFilterFactoryBean(){        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();        shiroFilter.setSecurityManager(defaultWebSecurityManager());        //使自定义过滤器生效        shiroFilter.setFilters(filters());        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());        shiroFilter.setLoginUrl("/login");        shiroFilter.setUnauthorizedUrl("/login");        return shiroFilter;    }}

4、缓存对象SimpleMapCache

package com.itheima.shiro.core.base;import com.itheima.shiro.utils.EmptyUtil;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import java.io.Serializable;import java.util.Collection;import java.util.Collections;import java.util.Map;import java.util.Set;/** * @Description 缓存实现类, 实现序列 接口方便对象存储于第三方容器(Map存放键值对) */public class SimpleMapCache implements Cache, Serializable {    private final Map attributes;    private final String name;    public SimpleMapCache(String name, Map backingMap) {        if (name == null)            throw new IllegalArgumentException("Cache name cannot be null.");        if (backingMap == null) {            throw new IllegalArgumentException("Backing map cannot be null.");        } else {            this.name = name;            attributes = backingMap;        }    }    public Object get(Object key) throws CacheException {        return attributes.get(key);    }    public Object put(Object key, Object value) throws CacheException {        return attributes.put(key, value);    }    public Object remove(Object key) throws CacheException {        return attributes.remove(key);    }    public void clear() throws CacheException {        attributes.clear();    }    public int size() {        return attributes.size();    }    public Set keys() {        Set keys = attributes.keySet();        if (!keys.isEmpty())            return Collections.unmodifiableSet(keys);        else            return Collections.emptySet();    }    public Collection values() {        Collection values = attributes.values();        if (!EmptyUtil.isNullOrEmpty(values))            return Collections.unmodifiableCollection(values);        else            return Collections.emptySet();    }    @Override    public String toString() {        return "SimpleMapCache [attributes=" + attributes + ", name=" + name                + ", keys()=" + keys() + ", size()=" + size() + ", values()="                + values() + "]";    }}

5、ShiroRedissionSerialize序列化工具

package com.itheima.shiro.utils;import lombok.extern.log4j.Log4j2;import org.apache.shiro.codec.Base64;import java.io.*;/** * @Description:实现shiro会话的序列化存储 */@Log4j2public class ShiroRedissionSerialize {    public static Object deserialize(String str) {        if (EmptyUtil.isNullOrEmpty(str)) {            return null;        }        ByteArrayInputStream bis = null;        ObjectInputStream ois = null;        Object object=null;        try {            bis = new ByteArrayInputStream(EncodesUtil.decodeBase64(str));            ois = new ObjectInputStream(bis);            object = ois.readObject();        } catch (IOException |ClassNotFoundException e) {            log.error("流读取异常:{}",e);        } finally {            try {                bis.close();                ois.close();            } catch (IOException e) {                log.error("流读取异常:{}",e);            }        }        return object;    }    public static String serialize(Object obj) {        if (EmptyUtil.isNullOrEmpty(obj)) {            return null;        }        ByteArrayOutputStream bos = null;        ObjectOutputStream oos = null;        String base64String = null;        try {            bos = new ByteArrayOutputStream();            oos = new ObjectOutputStream(bos);            oos.writeObject(obj);            base64String = EncodesUtil.encodeBase64(bos.toByteArray());        } catch (IOException e) {            log.error("流写入异常:{}",e);        } finally {            try {                bos.close();                oos.close();            } catch (IOException e) {                log.error("流写入异常:{}",e);            }        }        return base64String;    }}

6、缓存服务接口SimpleCacheService

SimpleCacheService

package com.itheima.shiro.core;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;/** * @Description 简单的缓存管理接口 */public interface SimpleCacheService {    /**     * 功能说明::新增缓存堆到管理器
*/ void createCache(String cacheName, Cache cache) throws CacheException; /** * 方法名::getCache
* 功能说明::获取缓存堆
*/ Cache getCache(String cacheName) throws CacheException; /** * 方法名::removeCache
* 功能说明::移除缓存堆
*/ void removeCache(String cacheName) throws CacheException; /** * 方法名::updateCahce
* 功能说明::更新缓存堆
*/ void updateCahce(String cacheName, Cache cache) throws CacheException;}

SimpleCacheServiceImpl

调用RedissonClient去实现缓存,同时使用ShiroRedissionSerialize实现序列化

package com.itheima.shiro.core.impl;import com.itheima.shiro.constant.CacheConstant;import com.itheima.shiro.core.SimpleCacheService;import com.itheima.shiro.utils.ShiroRedissionSerialize;import lombok.extern.log4j.Log4j2;import org.apache.shiro.SecurityUtils;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.redisson.api.RBucket;import org.redisson.api.RedissonClient;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.util.concurrent.TimeUnit;/** * * @Description 简单的缓存管理接口的实现 */@Log4j2@Componentpublic class SimpleCacheServiceImpl implements SimpleCacheService {    @Resource(name = "redissonClientForShiro")    RedissonClient redissonClient;    @Override    public void createCache(String name, Cache cache){        RBucket bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);        bucket.trySet(ShiroRedissionSerialize.serialize(cache), SecurityUtils.getSubject().getSession().getTimeout()/1000, TimeUnit.SECONDS);    }    @SuppressWarnings("unchecked")    @Override    public Cache getCache(String name) throws CacheException {        RBucket bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);        return (Cache) ShiroRedissionSerialize.deserialize(bucket.get());    }    @Override    public void removeCache(String name) throws CacheException {        RBucket bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);        bucket.delete();    }    @Override    public void updateCahce(String name, Cache cache){        RBucket bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);        bucket.set(ShiroRedissionSerialize.serialize(cache), SecurityUtils.getSubject().getSession().getTimeout()/1000, TimeUnit.MILLISECONDS);    }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值