shiro使用redis实现将菜单权限进行缓存

Posted 健康平安的活着

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shiro使用redis实现将菜单权限进行缓存相关的知识,希望对你有一定的参考价值。

一 redis的安装

参考文章:https://blog.csdn.net/u011066470/article/details/114794800

二  redis整合shiro

2.1 启动redis服务端

[root@localhost ~]# cd /usr/local/redis
[root@localhost redis]# ps -ef|grep redis
root       2947   2898  0 09:48 pts/0    00:00:00 grep --color=auto redis
[root@localhost redis]# ls
bin
[root@localhost redis]# cd bin
[root@localhost bin]# ls
dump.rdb         redis-check-aof  redis-cli       redis-server
redis-benchmark  redis-check-rdb  redis-sentinel
[root@localhost bin]# ./redis-server  /bonc-kecheng-jingxiang/redis-6.2.1/redis.conf
3106:C 02 Jun 2021 09:59:05.144 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3106:C 02 Jun 2021 09:59:05.144 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=3106, just started
3106:C 02 Jun 2021 09:59:05.144 # Configuration loaded
3106:M 02 Jun 2021 09:59:05.144 * Increased maximum number of open files to 10032 (it was originally set to 1024).
3106:M 02 Jun 2021 09:59:05.144 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.2.1 (00000000/0) 64 bit
  .-`` .-```.  ```\\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 3106
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

3106:M 02 Jun 2021 09:59:05.145 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
3106:M 02 Jun 2021 09:59:05.145 # Server initialized
3106:M 02 Jun 2021 09:59:05.145 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
3106:M 02 Jun 2021 09:59:05.146 * Loading RDB produced by version 6.2.1
3106:M 02 Jun 2021 09:59:05.146 * RDB age 36704 seconds
3106:M 02 Jun 2021 09:59:05.146 * RDB memory usage when created 0.85 Mb
3106:M 02 Jun 2021 09:59:05.146 * DB loaded from disk: 0.001 seconds
3106:M 02 Jun 2021 09:59:05.146 * Ready to accept connections

2.2 启动redis客户端

[root@localhost ~]# cd /usr/local/redis
[root@localhost redis]# cd bin
[root@localhost bin]# ls
dump.rdb         redis-check-aof  redis-cli       redis-server
redis-benchmark  redis-check-rdb  redis-sentinel
[root@localhost bin]# ./redis-cli
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> 

2.3 配置pom文件

      <!--redis整合springboot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2.4 配置redis连接

#redis
spring.redis.port=6379
spring.redis.host=172.16.71.22
spring.redis.database=0

2.5 开发RedisCacheManager

package com.shiro.ljf.demo.sptshirodemo.shiro.cache;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;

//自定义shiro缓存管理器
public class RedisCacheManager implements CacheManager {

    //参数1:认证或者是授权缓存的统一名称
    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        System.out.println(cacheName);
        return new RedisCache<K,V>(cacheName);
    }
}

 2.6 开RedisCache实现

package com.shiro.ljf.demo.sptshirodemo.shiro.cache;

import com.shiro.ljf.demo.sptshirodemo.utils.ApplicationContextUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Collection;
import java.util.Set;

//自定义redis缓存的实现
public class RedisCache<k,v> implements Cache<k,v> {

    private String cacheName;

    public RedisCache() {
    }

    public RedisCache(String cacheName) {
        this.cacheName = cacheName;
    }

    @Override
    public v get(k k) throws CacheException {
        System.out.println("get key:"+k);
        return (v) getRedisTemplate().opsForHash().get(this.cacheName,k.toString());
    }

    @Override
    public v put(k k, v v) throws CacheException {
        System.out.println("put key: "+k);
        System.out.println("put value:"+v);
        getRedisTemplate().opsForHash().put(this.cacheName,k.toString(),v);
        return null;
    }

    @Override
    public v remove(k k) throws CacheException {
        System.out.println("=============remove=============");
        return (v) getRedisTemplate().opsForHash().delete(this.cacheName,k.toString());
    }

    @Override
    public void clear() throws CacheException {
        System.out.println("=============clear==============");
        getRedisTemplate().delete(this.cacheName);
    }

    @Override
    public int size() {
        return getRedisTemplate().opsForHash().size(this.cacheName).intValue();
    }

    @Override
    public Set<k> keys() {
        return getRedisTemplate().opsForHash().keys(this.cacheName);
    }

    @Override
    public Collection<v> values() {
        return getRedisTemplate().opsForHash().values(this.cacheName);
    }

    private RedisTemplate getRedisTemplate(){
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

2.7 自定义salt序列化

  • 由于shiro中提供的simpleByteSource实现没有实现序列化,所有在认证时出现错误信息

  • 解决方案: 需要自动salt实现序列化

2.自定义的myByteSource类:

package com.shiro.ljf.demo.sptshirodemo.utils;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.util.ByteSource;

import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Arrays;

//自定义salt实现  实现序列化接口
public class MyByteSource implements ByteSource,Serializable {

    private  byte[] bytes;
    private String cachedHex;
    private String cachedBase64;

    public MyByteSource(){

    }

    public MyByteSource(byte[] bytes) {
        this.bytes = bytes;
    }

    public MyByteSource(char[] chars) {
        this.bytes = CodecSupport.toBytes(chars);
    }

    public MyByteSource(String string) {
        this.bytes = CodecSupport.toBytes(string);
    }

    public MyByteSource(ByteSource source) {
        this.bytes = source.getBytes();
    }

    public MyByteSource(File file) {
        this.bytes = (new BytesHelper()).getBytes(file);
    }

    public MyByteSource(InputStream stream) {
        this.bytes = (new BytesHelper()).getBytes(stream);
    }

    public static boolean isCompatible(Object o) {
        return o instanceof byte[] || o instanceof char[] || o instanceof String || o instanceof ByteSource || o instanceof File || o instanceof InputStream;
    }

    public byte[] getBytes() {
        return this.bytes;
    }

    public boolean isEmpty() {
        return this.bytes == null || this.bytes.length == 0;
    }

    public String toHex() {
        if (this.cachedHex == null) {
            this.cachedHex = Hex.encodeToString(this.getBytes());
        }

        return this.cachedHex;
    }

    public String toBase64() {
        if (this.cachedBase64 == null) {
            this.cachedBase64 = Base64.encodeToString(this.getBytes());
        }

        return this.cachedBase64;
    }

    public String toString() {
        return this.toBase64();
    }

    public int hashCode() {
        return this.bytes != null && this.bytes.length != 0 ? Arrays.hashCode(this.bytes) : 0;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (o instanceof ByteSource) {
            ByteSource bs = (ByteSource)o;
            return Arrays.equals(this.getBytes(), bs.getBytes());
        } else {
            return false;
        }
    }

    private static final class BytesHelper extends CodecSupport {
        private BytesHelper() {
        }

        public byte[] getBytes(File file) {
            return this.toBytes(file);
        }

        public byte[] getBytes(InputStream stream) {
            return this.toBytes(stream);
        }
    }

}

 2.8 验证

1.关闭防火墙

[root@localhost ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-06-02 09:47:20 CST; 1h 17min ago
     Docs: man:firewalld(1)
 Main PID: 783 (firewalld)
    Tasks: 2
   CGroup: /system.slice/firewalld.service
           └─783 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:45 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Jun 02 09:47:46 localhost.localdomain firewalld[783]: WARNING: COMMAND_FAILED...
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost ~]# systemctl stop  firewalld
[root@localhost ~]# 

2.将服务启动起来

3.使用用户ljf进行登录

 

跳转到登录页面

 

多次刷页面

可以看到:不再查询数据库,没有查询数据库的日志,

查看redis数据库:

127.0.0.1:6379> keys *
1) "my-authenticationCache"
2) "com.shiro.ljf.demo.sptshirodemo.shiro.CustomerRealm.authorizationCache"
127.0.0.1:6379> hgetall my-authenticationCache
1) "ljf"
2) "\\xac\\xed\\x00\\x05sr\\x00/org.apache.shiro.authc.SimpleAuthenticationInfo\\x83\\xc0\\x15@`\\xea%,\\x02\\x00\\x03L\\x00\\x0bcredentialst\\x00\\x12Ljava/lang/Object;L\\x00\\x0fcredentialsSaltt\\x00\\"Lorg/apache/shiro/util/ByteSource;L\\x00\\nprincipalst\\x00.Lorg/apache/shiro/subject/PrincipalCollection;xpt\\x00 d12dfd006876d2539291d47d802b3c66sr\\x002com.shiro.ljf.demo.sptshirodemo.utils.MyByteSource\\xaf\\x00\\xe6\\xbb\\x05\\x86\\xc8\\xf0\\x02\\x00\\x03[\\x00\\x05bytest\\x00\\x02[BL\\x00\\x0ccachedBase64t\\x00\\x12Ljava/lang/String;L\\x00\\tcachedHexq\\x00~\\x00\\bxpur\\x00\\x02[B\\xac\\xf3\\x17\\xf8\\x06\\bT\\xe0\\x02\\x00\\x00xp\\x00\\x00\\x00\\bQWW!RgLwppsr\\x002org.apache.shiro.subject.SimplePrincipalCollection\\xa8\\x7fX%\\xc6\\xa3\\bJ\\x03\\x00\\x01L\\x00\\x0frealmPrincipalst\\x00\\x0fLjava/util/Map;xpsr\\x00\\x17java.util.LinkedHashMap4\\xc0N\\\\\\x10l\\xc0\\xfb\\x02\\x00\\x01Z\\x00\\x0baccessOrderxr\\x00\\x11java.util.HashMap\\x05\\a\\xda\\xc1\\xc3\\x16`\\xd1\\x03\\x00\\x02F\\x00\\nloadFactorI\\x00\\tthresholdxp?@\\x00\\x00\\x00\\x00\\x00\\x0cw\\b\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x01t\\x005com.shiro.ljf.demo.sptshirodemo.shiro.CustomerRealm_0sr\\x00\\x17java.util.LinkedHashSet\\xd8l\\xd7Z\\x95\\xdd*\\x1e\\x02\\x00\\x00xr\\x00\\x11java.util.HashSet\\xbaD\\x85\\x95\\x96\\xb8\\xb74\\x03\\x00\\x00xpw\\x0c\\x00\\x00\\x00\\x10?@\\x00\\x00\\x00\\x00\\x00\\x01t\\x00\\x03ljfxx\\x00w\\x01\\x01q\\x00~\\x00\\x11x"
127.0.0.1:6379> hget my-authenticationCache ljf
"\\xac\\xed\\x00\\x05sr\\x00/org.apache.shiro.authc.SimpleAuthenticationInfo\\x83\\xc0\\x15@`\\xea%,\\x02\\x00\\x03L\\x00\\x0bcredentialst\\x00\\x12Ljava/lang/Object;L\\x00\\x0fcredentialsSaltt\\x00\\"Lorg/apache/shiro/util/ByteSource;L\\x00\\nprincipalst\\x00.Lorg/apache/shiro/subject/PrincipalCollection;xpt\\x00 d12dfd006876d2539291d47d802b3c66sr\\x002com.shiro.ljf.demo.sptshirodemo.utils.MyByteSource\\xaf\\x00\\xe6\\xbb\\x05\\x86\\xc8\\xf0\\x02\\x00\\x03[\\x00\\x05bytest\\x00\\x02[BL\\x00\\x0ccachedBase64t\\x00\\x12Ljava/lang/String;L\\x00\\tcachedHexq\\x00~\\x00\\bxpur\\x00\\x02[B\\xac\\xf3\\x17\\xf8\\x06\\bT\\xe0\\x02\\x00\\x00xp\\x00\\x00\\x00\\bQWW!RgLwppsr\\x002org.apache.shiro.subject.SimplePrincipalCollection\\xa8\\x7fX%\\xc6\\xa3\\bJ\\x03\\x00\\x01L\\x00\\x0frealmPrincipalst\\x00\\x0fLjava/util/Map;xpsr\\x00\\x17java.util.LinkedHashMap4\\xc0N\\\\\\x10l\\xc0\\xfb\\x02\\x00\\x01Z\\x00\\x0baccessOrderxr\\x00\\x11java.util.HashMap\\x05\\a\\xda\\xc1\\xc3\\x16`\\xd1\\x03\\x00\\x02F\\x00\\nloadFactorI\\x00\\tthresholdxp?@\\x00\\x00\\x00\\x00\\x00\\x0cw\\b\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x01t\\x005com.shiro.ljf.demo.sptshirodemo.shiro.CustomerRealm_0sr\\x00\\x17java.util.LinkedHashSet\\xd8l\\xd7Z\\x95\\xdd*\\x1e\\x02\\x00\\x00xr\\x00\\x11java.util.HashSet\\xbaD\\x85\\x95\\x96\\xb8\\xb74\\x03\\x00\\x00xpw\\x0c\\x00\\x00\\x00\\x10?@\\x00\\x00\\x00\\x00\\x00\\x01t\\x00\\x03ljfxx\\x00w\\x01\\x01q\\x00~\\x00\\x11x"
127.0.0.1:6379> 

 

以上是关于shiro使用redis实现将菜单权限进行缓存的主要内容,如果未能解决你的问题,请参考以下文章

java SSM框架 websocket即时通讯 代码生成器 shiro redis 后台框架源码

shiro 分布式缓存用户信息

SpringBoot项目+Shiro(权限框架)+Redis(缓存)集成

Spring boot后台搭建二为Shiro权限控制添加Redis缓存

Shiro整合Springboot缓存之Redis实现

基于Spring Boot+Security+Redis权限管理系统,权限控制采用RBAC