文章目录
1.使用EhCache实现缓存
shiro 默认使用 EhCache实现本地缓存
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点
1.引入maven依赖
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.7.1</version>
</dependency>
1.1开启缓存
在realm里面开启缓存
// 开启缓存
realm.setCacheManager(new EhCacheManager());
// 开启全局缓存
realm.setCachingEnabled(true);
// 开启认证缓存
realm.setAuthenticationCachingEnabled(true);
// 开启授权缓存
realm.setAuthorizationCachingEnabled(true);
// 设置授权缓存的名称,设置验证缓存的名称,可以不用设置,默认有
realm.setAuthenticationCacheName("authenticationCacheName");
realm.setAuthorizationCacheName("authorizationCacheName");
2.使用redis实现缓存
2.1引入maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.2在application配置redis连接参数
# redis的端口
spring.redis.port=6379
# redis所在的服务器IP
spring.redis.host=localhost
# 使用的哪一个数据库
spring.redis.database=0
2.3通过代码的方式获取spring框架applicationcontext对象
applicationcontextUtil工具类
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static Object getBean(String name) {
return context.getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return context.getBean(name, clazz);
}
}
2.4RedisCacheManager与RedisCache
我们要实现redis缓存,我们就必须自己实现shiro提供的CacheMananger接口和Cache接口
RedisCache
@Data
@AllArgsConstructor
@SuppressWarnings("unchecked")
public class RedisCache<k, v> implements Cache<k, v> {
private String cacheName;
@SuppressWarnings("rawtypes")
private RedisTemplate getRedisTemplate() {
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
@Override
public v get(k k) throws CacheException {
return (v) getRedisTemplate().opsForHash().get(this.cacheName, k.toString());
}
@Override
public v put(k k, v v) throws CacheException {
getRedisTemplate().opsForHash().put(this.cacheName, 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 {
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);
}
}
RedisCacheMananger
public class RedisCacheMananger implements CacheManager {
/**
* name参数是我们设置的AuthenticationCache与AuthorizationCache的名
*
* 不设置默认默认名称
* cn.liuhao.springboot_shiro01.realm.CustomerRealm.authenticationCache
* cn.liuhao.springboot_shiro01.realm.CustomerRealm.authorizationCache
*/
@Override
public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
System.out.println(cacheName);
return new RedisCache<K, V>(cacheName);
}
}
2.5shiroConfig开启缓存
@Configuration
public class ShiroConfig {
// 2.创建 securityMananger
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(CustomerRealm realm) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
// 创建realm使用的hash凭证器
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
// 告诉凭证器加密的类型
matcher.setHashAlgorithmName("md5");
// 告诉凭证器使用hash散列加密的次数
matcher.setHashIterations(1024);
// 注入realm
realm.setCredentialsMatcher(matcher);
// 给securityMananger设置realm
defaultWebSecurityManager.setRealm(realm);
// 开启缓存
realm.setCacheManager(new RedisCacheMananger());
// 开启全局缓存
realm.setCachingEnabled(true);
// 开启认证缓存
realm.setAuthenticationCachingEnabled(true);
// 开启授权缓存
realm.setAuthorizationCachingEnabled(true);
// 设置授权缓存的名称,设置验证缓存的名称,可以不用设置,默认有
// realm.setAuthenticationCacheName("authenticationCacheName");
// realm.setAuthorizationCacheName("authorizationCacheName");
return defaultWebSecurityManager;
}
}
shiro整合redis注意问题
1.实体类都需要添加序列化接口
我们自定义的实体类,都需要实现
Serializable
接口
2.simpleByteSource不能实例化
错误解释: 由于shiro中提供的simpleByteSource实现没有实现序列化,所有在认证时出现错误信息
解决方案: 需要自动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 com.lut.shiro.salt.MyByteSource.BytesHelper()).getBytes(file);
}
public MyByteSource(InputStream stream) {
this.bytes = (new com.lut.shiro.salt.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);
}
}
在 realm中使用自定义的MyByteSource