1.引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
2.配置yml文件
3.配置缓存文件
观察一下原来的 Realm配置
当用户通过了AuthrenticationInfo(认证)之后会进行AuthorizationInfo(授权),但是此时如果每个用都在进入的时候进行查询操作数据,这样就会让数据库的吞吐量加大最终导致数据库挂掉。所以现在就需要做缓存来支持我们需要的功能。
这是根据角色(role)来获取对应的权限(permission)
3.1查看默认缓存
首先查看一下我们本来的Realm配置信息
下图是使用的最原始EhCacheManager配置的缓存信息,但是我们需要的是将缓存放入Redis中
3.2配置RedisCache
我们查看一下EhCacheManager这个类的信息
默认实现了shiro提供的CacheManager
3.3自定义RedisCache
根据上面的信息可以得知,如果我们需要定义一个RedisCache就必须实现一下shiro提供的CacheManager
返回的值是一个Cache<K, V>,我们可以查看一下它的实现类有什么
是不是和上面的EhCacheManager()似曾相识的感觉?所以问题解决,我们可以进行实现Cache来重写里面的方法,实现自定义的目的
/**
* description: RedisCache 缓存配置
* date: 2021/6/11 16:43
* author: XiaoCoder
* version: 1.0
*/
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 k:" + k);
return (v) getRedisTemplate().opsForValue().get(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().opsForValue().set(k.toString(), v);
return null;
}
@Override
public v remove(k k) throws CacheException {
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() {
// 这里是通过自定义的获取bean的方法,进行转化得到的数据
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
// Creates a new StringRedisSerializer using UTF-8.序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
// Creates a new StringRedisSerializer using UTF-8.序列化方式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
获取bean的工具类
3.4 配置实体类的序列化
让实体类
role
,permission
,user
实现Serializable
3.4.1 注意:salt(盐)
盐也需要进行相同的序列号。如果不序列化盐,在Redis缓存和JVM数据进行交互的时候会报错
/**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String account = usernamePasswordToken.getUsername();
User user = userService.getOne(new QueryWrapper<User>().eq("username", account));
if (user == null) {
return null;
}
return new SimpleAuthenticationInfo(user, user.getPassword(), new MyByteSource(user.getSalt()), this.getName());
}
创建一个MyByteSource类实现ByteSource, Serializable 重写 Shiro默认的序列化规则
/**
* description: MyByteSource
* date: 2021/6/11 18:45
* author: XiaoCoder
* version: 1.0
*/
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 MyByteSource.BytesHelper()).getBytes(file);
}
public MyByteSource(InputStream stream) {
this.bytes = (new MyByteSource.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);
}
}
}