Springboot 整合redis和 shiro遇到问题
总结
- shiro和 jackson 版本问题
- redistemplate 的反序列化问题
- ByteSource的缺少构造器问题
版本
名称 | 版本 |
---|---|
springboot | 2.0.2.RELEASE |
shiro | 1.4.0 |
jackson | 2.9.2 |
具体代码
RedisTemplate
定义RedisTemplate自定义 cache 的时候可以引用,具体可以看注释
@Bean(name = "redisTemplate")
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//只序列化必要shiro字段
String [] needSerialize = {"realmPrincipals"};
objectMapper.addMixIn(SimplePrincipalCollection.class, IncludShiroFields.class);
objectMapper.setFilters(new SimpleFilterProvider().addFilter("shiroFilter", SimpleBeanPropertyFilter.filterOutAllExcept(needSerialize)));
// 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//string的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用string的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也采用string的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
IncludShiroFields
序列化SimplePrincipalCollection对象时只有通过IncludShiroFields接口定义的属性会被包含在JSON中
@JsonFilter("shiroFilter")
public interface IncludShiroFields {
}
MCahce
package com.xxx.manager.redis;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Set;
@Component
public class MCahce <K,V> implements Cache<K,V> {
//redis key
private final K prefix = (K)"shiro_cache";
@Autowired
private RedisTemplate redisTemplate;
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
//------------------------
@Override
public V get(K key) throws CacheException {
Object o = redisTemplate.opsForHash().get(prefix,key);
return o == null ? null : (V) o;
}
@Override
public V put(K key, V value) throws CacheException {
V old = this.get(key);
redisTemplate.opsForHash().put(prefix,key,value);
return old;
}
@Override
public V remove(K key) throws CacheException {
V old = this.get(key);
redisTemplate.opsForHash().delete(prefix,key);
return old;
}
public void removeOld(K key) throws CacheException {
redisTemplate.opsForHash().delete(prefix,key);
}
@Override
public void clear() throws CacheException {
redisTemplate.delete(prefix);
}
@Override
public int size() {
return redisTemplate.opsForHash().size(prefix).intValue();
}
@Override
public Set<K> keys() {
return redisTemplate.opsForHash().keys(prefix);
}
@Override
public Collection<V> values() {
return redisTemplate.opsForHash().values(prefix);
}
}
MyCacheManager
package com.xxx.manager.redis;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyCacheManager extends AbstractCacheManager {
@Autowired
private MCahce mCahce;
@Override
protected Cache createCache(String name) throws CacheException {
return mCahce;
}
}
MySimpleByteSource
package com.bric.manager.redis;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Arrays;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.util.ByteSource;
public class MySimpleByteSource implements ByteSource, Serializable {
private static final long serialVersionUID = 5175082362119580768L;
private byte[] bytes;
private String cachedHex;
private String cachedBase64;
public MySimpleByteSource(){
}
public MySimpleByteSource(byte[] bytes) {
this.bytes = bytes;
}
public MySimpleByteSource(char[] chars) {
this.bytes = CodecSupport.toBytes(chars);
}
public MySimpleByteSource(String string) {
this.bytes = CodecSupport.toBytes(string);
}
public MySimpleByteSource(ByteSource source) {
this.bytes = source.getBytes();
}
public MySimpleByteSource(File file) {
this.bytes = (new MySimpleByteSource.BytesHelper()).getBytes(file);
}
public MySimpleByteSource(InputStream stream) {
this.bytes = (new MySimpleByteSource.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 void setBytes(byte[] bytes) {
this.bytes = bytes;
}
@Override
public byte[] getBytes() {
return this.bytes;
}
@Override
public String toHex() {
if(this.cachedHex == null) {
this.cachedHex = Hex.encodeToString(this.getBytes());
}
return this.cachedHex;
}
@Override
public String toBase64() {
if(this.cachedBase64 == null) {
this.cachedBase64 = Base64.encodeToString(this.getBytes());
}
return this.cachedBase64;
}
@Override
public boolean isEmpty() {
return this.bytes == null || this.bytes.length == 0;
}
@Override
public String toString() {
return this.toBase64();
}
@Override
public int hashCode() {
return this.bytes != null && this.bytes.length != 0 ? Arrays.hashCode(this.bytes) : 0;
}
@Override
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);
}
}
}
以上代码参考他人文章,存放便于自己总结。