ITPub博客

首页 > 数据库 > 数据库开发技术 > Spring Boot集成shiro之使用redis缓存demo

Spring Boot集成shiro之使用redis缓存demo

原创 数据库开发技术 作者:hblog 时间:2024-05-23 08:16:18 0 删除 编辑


1.背景

上次发了这篇文章《Spring Boot集成Shiro快速入门Demo》后,有网友“just.blue”后台反馈集成redis有点问题,今天特地把集成过程发出来

2.为什么要使用cache

用来减轻数据库的访问压力,从而提升查询效率。

3.Shiro使用Redis做缓存

redis环境准备

参照代码工程li面redis模块里面docker,按照要求启动即可

引入pom,xml

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

redis配置

spring:  redis:    database: 0    port: 6379    host: 127.0.0.1    password: 123456    timeout=3000:    jedis:      pool:        max-active: 8        max-idle: 8        max-wait: -1        min-idle: 0

cache接口实现

创建RedisCacheManager实现CacheManager接口

package com.et.shiro.cache;
import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;
public class RedisCacheManager implements CacheManager { @Override public <K, V> Cache<K, V> getCache(String cacheKey) throws CacheException { return new RedisCache<>(cacheKey); }}

创建RedisCache实现Cache接口

package com.et.shiro.cache;
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;
public class RedisCache<K, V> implements Cache<K, V> { private String cacheName;
public RedisCache() { }
public RedisCache(String cacheName) { this.cacheName = cacheName; }

private RedisTemplate getRedisTemplate() { RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtil.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().opsForHash().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); }}

获取bean工具类

package com.et.shiro.cache;
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;
@Componentpublic class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }
public static <T> T getBean(String beanName) { return (T)applicationContext.getBean(beanName); }
public static <T> T getBean(Class<T> className) { return applicationContext.getBean(className); }}

由于自定义realm中认证所需要的盐值内部并没有实现序列化接口,所以我们需要自己定一个MyByteSource继承SimpleByteSource并实现Serializable接口

package com.et.shiro.config;
import org.apache.shiro.util.SimpleByteSource;
import java.io.Serializable;
public class MyByteSource extends SimpleByteSource implements Serializable { public MyByteSource(String string) { super(string); }}

在自定义的Realm中需要在认证的方法中,改写salt的处理。

@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)        throws AuthenticationException {    System.out.println("MyShiroRealm.doGetAuthenticationInfo()");    String username = (String)token.getPrincipal();    System.out.println(token.getCredentials());    //query user by username    //in here ,you can cache some data for efficient    UserInfo userInfo = userInfoService.findByUsername(username);    System.out.println("----->>userInfo="+userInfo);    if(userInfo == null){        return null;    }    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(            userInfo, //username            userInfo.getPassword(), //password            new MyByteSource(userInfo.getCredentialsSalt()),            //ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt            getName()  //realm name    );    return authenticationInfo;}

注意实体类(角色类,用户类,权限类)要记得实现Serializable接口 最后在Shiro配置类中开启缓存,使用我们自己定义的RedisManager

@Beanpublic MyShiroRealm myShiroRealm(){   MyShiroRealm myShiroRealm = new MyShiroRealm();   myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());// 设置解密规则   // 开启全局缓存   myShiroRealm.setCachingEnabled(true);   // 开启认证缓存   myShiroRealm.setAuthenticationCachingEnabled(true);   // 设置认证缓存管理的名字   myShiroRealm.setAuthenticationCacheName("authenticationCache");   // 开启授权缓存管理   myShiroRealm.setAuthorizationCachingEnabled(true);   // 设置授权缓存管理的名字   myShiroRealm.setAuthorizationCacheName("authorizationCache");   // 开启Redis缓存   myShiroRealm.setCacheManager(new RedisCacheManager());   return myShiroRealm;}

以上只是一些关键代码,所有代码请参见下面代码仓库


代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

启动项目,访问http://127.0.0.1:8088/userInfo/userAdd,会跳转到登录页,输入admin 123456,查看redis是否缓存了登录用户,第一次会从数据库中查询,并通过RedisTemplate的put方法将用户信息装入缓存,下次再刷新首页就会从redis中查询权限,授权等信息。退出时会调用RedisTemplate中的remove方法清除向对应的用户缓存。

5.引用

  • http://www.liuhaihua.cn/archives/710596.html

  • https://www.cnblogs.com/dataoblogs/p/14121884.html

原文作者:HBLOG;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-05-04

  • 博文量
    210
  • 访问量
    111756