【Spring】权限管理_Shiro缓存授权信息

应用场景

用户权限认证需要查询数据库中角色与权限关系,Shiro负责权限认证。用户请求资源,后端逻辑都需要查询数据库中的信息交给Shiro做权限验证,这种频发查询准静态数据的做法会消耗数据库资源同时也会API性能。基于Redis缓存用户角色关系,可以有效提供API性能。

环境说明

  • JDK 1.8
  • Springboot 2.1.6
  • Redis 5.0

Shiro依赖包

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

Redis配置

Redisvalue序列化方式需要指定Jackson2JsonRedisSerializer,需要对org.apache.shiro.authz.SimpleAuthorizationInfo序列化。

    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        RedisSerializer<?> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);// key序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
        redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

继承CacheManger

@Slf4j
public class RedisShiroCacheManager extends AbstractCacheManager {

    private RedisService redisService;

    public RedisShiroCacheManager(RedisService redisService) {
        this.redisService = redisService;
    }



    /**
     * 认证或者授权对应的缓存名称key
     */
    @Override
    protected Cache createCache(String s) throws CacheException {
        // 将Spring Bean redisService注入到RedisShiroCache
        Cache cache = new RedisShiroCache( redisService, s);
        return cache;
    }

}

实现Redis读写


@Slf4j
public class RedisShiroCache<K, V> implements Cache<K, V> {

    private RedisService redisService;
    private String cacheName;


    public RedisShiroCache() {
    }

    public RedisShiroCache(RedisService redisService, String cacheName) {
        this.redisService = redisService;
        this.cacheName = cacheName;
    }

    @Override
    public V get(K k) throws CacheException {
        Object hget = redisService.hget(this.cacheName, k.toString());
        log.info("get({}) and value [{}]", k, hget);
        return (V) hget;
    }

    @Override
    public V put(K k, V v) throws CacheException {
        redisService.hset(this.cacheName, k.toString(), v);
        log.info("set({},{}", k, v);

        return null;
    }

    @Override
    public V remove(K k) throws CacheException {
        return null;
    }

    @Override
    public void clear() throws CacheException {

    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public Set<K> keys() {
        return null;
    }

    @Override
    public Collection<V> values() {
        return null;
    }
}

配置securityManager


@Slf4j
@Configuration
public class ShirosConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        log.info("注入Shiro的Web过滤器-->shiroFilter", ShiroFilterFactoryBean.class);
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //Shiro的核心安全接口,这个属性是必须的
        shiroFilterFactoryBean.setSecurityManager(securityManager);
		
		......

        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(OAuth2Realm oAuth2Realm, RedisService redisService) {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        /**
         * 设置Redis缓存
         */
         // 开启缓存
        oAuth2Realm.setCachingEnabled(true);
        oAuth2Realm.setAuthorizationCachingEnabled(true);
        oAuth2Realm.setAuthorizationCacheName("authorizationCache");
        oAuth2Realm.setAuthorizationCachingEnabled(true);
        oAuth2Realm.setAuthenticationCacheName("authenticationCache");
        // 指定缓存管理器
        defaultSecurityManager.setCacheManager(new RedisShiroCacheManager(redisService));
        defaultSecurityManager.setRealm(oAuth2Realm);
        return defaultSecurityManager;
    }

计划

  1. 主要对授权部分,缓存角色权限信息;但是每次调用API还是会调用doGetAuthenticationInfo方法,这就涉及到session缓存;
  2. 既然使用到了缓存,就需要保证缓存数据与Mysql一致性。
  3. 开发RememberMe功能
  4. 同一账号不能同时登录
  5. 熟悉Shiro工作原理,不能硬着头皮写代码,否则效率十分低。

引用

  • https://blog.csdn.net/u010514380/article/details/82185451 【很详细】
  • https://blog.csdn.net/baidu_33969289/article/details/86670054
  • https://www.cnblogs.com/youzhibing/tag/shiro/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值