一、什么叫shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
----百度百科
二、shrio的基本组成
shiro主要有三个核心组件组成: Subject 、SecurityMannager 和Realms
其中
Subject :即"当前操作用户"
SecurityMannager: shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务
Realm: Realm充当了Shiro与应用安全数据间的"桥梁"或者"连接器",也就说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户以及其权限信息
所以,Realm相当于一个安全相关的DAO,它封装了数据源的连接细节,并在需要时将相关的数据提供给shiro,当配置Shiro时,你必须至少指定一个Realm,用于认证或授权,配置多个Realm是可以的,但是至少需要一个
常用的功能:
Authentication: 身份认证/登录(账号密码验证)
Authoriztion: 授权,即角色或者权限验证 (权限)
Session Manager: 会话管理,用户登录之后Session 相关管理
Cryptography: 用于密码的加密(一般是以md5进行加密)
Web Support: 集成于Web环境
Caching: 缓存,可以将用户信息、角色、权限等缓存到Redis中,这样就不用在每次去查询数据库
三、shiro与SpringBoot结合使用
1、pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>testShrio</name>
<description>this Project for Shrio</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
一个用户可以有多个角色,一个角色可以有多个权限。用户有用户名和用户密码,角色有角色名,权限有权限名。那么我们就可以创建以下实体类
User.java
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/14 22:50
* @Description
*/
@Data
@AllArgsConstructor
public class User {
private String id;
private String userName;
private String password;
private Set<Role> roles;
}
Role.java
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:08
* @Description
*/
@Data
@AllArgsConstructor
public class Role {
private String id;
private String roleName;
/**
* 角色对应的权限集合
*/
private Set<Permission> permissions;
}
Permission.java
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:13
* @Description 权限实体类
*/
@Data
@AllArgsConstructor
public class Permission {
private String id;
private String permissionsName;
}
用户信息查询接口以及实现类
LoginService.java
package com.example.demo.service;
import com.example.demo.model.User;
/**
* 登录接口
*/
public interface LoginService {
User getUserByName(String getMapByName);
}
LoginServiceImpl.java(用于组装用户和角色和权限的关系)
package com.example.demo.service.Impl;
import com.example.demo.model.Permission;
import com.example.demo.model.Role;
import com.example.demo.model.User;
import com.example.demo.service.LoginService;
import javafx.beans.property.ReadOnlySetProperty;
import org.apache.shiro.crypto.hash.Hash;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:15
* @Description 登录实现
*/
@Service
public class LoginServiceImpl implements LoginService {
@Override
public User getUserByName(String userName) {
return getMapByName(userName);
}
/**
* 模拟数据库查询
* @param userName
* @return
*/
private User getMapByName(String userName) {
Permission permission = new Permission("1","query");
Permission permission1 =new Permission("2","add");
Set<Permission> permissionSet = new HashSet<>();
permissionSet.add(permission);
permissionSet.add(permission1);
Role role = new Role("1","admin",permissionSet);
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
User user = new User("1","admin","123456",roleSet);
Map<String,User> map = new HashMap<>();
map.put(user.getUserName(),user);
Set<Permission> permissionSet1 = new HashSet<>();
permissionSet1.add(permission);
permissionSet1.add(permission1);
Role role1 = new Role("2","user",permissionSet1);
Set<Role> roleSet1 = new HashSet<>();
roleSet1.add(role1);
User user1 = new User("2","user","123456",roleSet1);
map.put(user1.getUserName(),user1);
return map.get(userName);
}
}
自定义Realm 用于查询用户的 角色和权限信息并保存到权限管理器中
上面说到Realm相当于一个DAO,用于将用户输入的信息与数据库中得数据进行相比较
所以这里需要在自定义的Realm中注入 LoginService用于信息的验证
package com.example.demo.config;
import com.example.demo.model.Permission;
import com.example.demo.model.Role;
import com.example.demo.model.User;
import com.example.demo.service.LoginService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:28
* @Description 自定义Relm 用于查询用户的角色和权限信息并保存到权限管理器中
*/
public class CustomRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* 根据当前登录人来返回对应授权配置类 权限的处理
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取登录的用户名
if(principalCollection.getPrimaryPrincipal() ==null) {
return null;
}
String name = (String) principalCollection.getPrimaryPrincipal();
// 查询用户的名称
User user = loginService.getUserByName(name);
// 添加角色和权限
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
for(Role role : user.getRoles()) {
// 添加角色
simpleAuthenticationInfo.addRole(role.getRoleName());
// 添加权限
for(Permission permission : role.getPermissions()) {
simpleAuthenticationInfo.addStringPermission(permission.getPermissionsName());
}
}
return simpleAuthenticationInfo;
}
/**
* 根据表单提交上的用户名来创建出 权限配置类 用于姓名和密码的校验
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (authenticationToken.getPrincipal() == null) {
return null;
}
// 获取用户信息
String name = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByName(name);
if(user ==null) {
return null;
} else {
// 这里验证authenticationToken 和 SimpleAuthenticationInfo 的信息
SimpleAuthenticationInfo simpleAuthorizationInfo = new SimpleAuthenticationInfo(name,user.getPassword(),getName());
return simpleAuthorizationInfo;
}
}
}
创建Shiro配置文件,将CustomeRealm和SecurityManager注入到Spring容器中
package com.example.demo.config;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import java.util.HashMap;
import java.util.Map;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:47
* @Description
*/
@Configuration
public class ShiroConfig {
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
// 将自己验证的方式加入到容器中
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager ();
defaultSecurityManager.setRealm(customRealm());
return defaultSecurityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<>();
// 登出
map.put("/logout","logout");
// 对所有用户进行认证
map.put("/**","authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
// 首页
shiroFilterFactoryBean.setSuccessUrl("/index");
// 错误页面 认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
制作登录Controller
package com.example.demo.controller;
import com.example.demo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.message.StringFormattedMessage;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 11:29
* @Description 登录请求
*/
@RestController
@Slf4j
public class LoginController {
@GetMapping("/login")
public String login(User user) {
if(StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())) {
return "请输入用户名和密码";
}
// 用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUserName(),user.getPassword());
try {
// 进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
}catch (UnknownAccountException e) {
log.error("用户名不存在",e);
return "用户名不存在";
} catch (AuthenticationException e) {
log.error("账号或者密码错误!",e);
return "账号或者密码错误!";
} catch (AuthorizationException e) {
log.error("没有权限!",e);
return "没有权限";
}
return "login success";
}
@RequiresRoles("admin")
@GetMapping("/admin")
public String admin() {
return "admin Success!";
}
@RequiresPermissions("query")
@GetMapping("/index")
public String index() {
return "index success";
}
@RequiresPermissions("add")
@GetMapping("/add")
public String add() {
return "add success";
}
}
全局增加异常信息捕获,用于捕获异常信息
package com.example.demo.aspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 11:54
* @Description
*/
@Slf4j
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler
@ResponseBody
public String ErrorHandler(AuthorizationException e) {
log.error("没有通过权限验证!",e);
return "没有通过权限验证";
}
}
启动项目,访问
http://localhost:8082/login?userName=admin&password=123456
暂时先写这么多,后面再写
五、SpringBoot +shiro 密码校验加密 +mybatis 数据库
上面配置的shiro在校验时是以明文的 方式进行校验,但往往开发 过程中数据库中得密码都是加密后存储到数据库中的。
shiroConfig.class中增加如下配置
// 将自己验证的方式加入到容器中
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
// 配置 加密 (在加密后,不配置的话会导致登陆密码失败)
customRealm.setCredentialsMatcher(new CustomCredentialsMatcher());
return customRealm;
}
创建自定义加密认证方式 CustomCredentialsMatcher.class
package com.example.demo.config;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.crypto.hash.SimpleHash;
/**
* 自定义认证加密方式
*/
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
//加密类型,密码,盐值,迭代次数
Object tokenCredentials = new SimpleHash("md5", token.getPassword(), token.getUsername(), 2).toHex();
//数据库存储密码
Object accountCredentials = getCredentials(info);
//将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
return equals(tokenCredentials, accountCredentials);
}
}
地址栏访问
http://localhost:8082/login?userName=admin&password=123456
打断点调试
六、SpringBoot+mybatis 数据库查询用户权限信息
pom.xml文件增加如下配置
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
application.yml 配置
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://localhost:3306/shiro?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: root
password: root
driverClassName: com.mysql.cj.jdbc.Driver
redis:
host: 127.0.0.1
port: 6379
jedis:
pool:
max-idle: 8
min-idle: 0
max-active: 8
max-wait: -1
timeout: 0
cache:
type: redis
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
cache-enabled: true #开启全局二级缓存 mybatis通过这个会使用CachingExecutor
LoginServiceImpl.class
package com.example.demo.service.Impl;
import com.example.demo.dao.LoginMapper;
import com.example.demo.model.Permission;
import com.example.demo.model.Role;
import com.example.demo.model.User;
import com.example.demo.service.LoginService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author lenovo
* @version 1.0
* @Date 2022/1/15 10:15
* @Description 登录实现
*/
@Service
public class LoginServiceImpl implements LoginService {
@Resource
private LoginMapper loginMapper;
@Cacheable(value = "user")
@Override
public User getUserByName(String userName) {
// return getMapByName(userName);
return loginMapper.getUserByName(userName);
}
/**
* 模拟数据库查询
* @param userName
* @return
*/
private User getMapByName(String userName) {
Permission permission = new Permission("1","query");
Permission permission1 =new Permission("2","add");
Set<Permission> permissionSet = new HashSet<>();
permissionSet.add(permission);
permissionSet.add(permission1);
Role role = new Role("1","admin",permissionSet);
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
User user = new User("1","admin","123456",roleSet);
Map<String,User> map = new HashMap<>();
map.put(user.getUserName(),user);
Set<Permission> permissionSet1 = new HashSet<>();
permissionSet1.add(permission);
permissionSet1.add(permission1);
Role role1 = new Role("2","user",permissionSet1);
Set<Role> roleSet1 = new HashSet<>();
roleSet1.add(role1);
User user1 = new User("2","user","123456",roleSet1);
map.put(user1.getUserName(),user1);
return map.get(userName);
}
}
LoginMapper.class
package com.example.demo.dao;
import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LoginMapper {
User getUserByName(String userName);
}
对应的xml文件 LoginMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.LoginMapper">
<resultMap id="UserMap" type="com.example.demo.model.User">
<id column="id" property="id" jdbcType="INTEGER"></id>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<collection property="roles" javaType="java.util.Set" column="id" select="selectRoles"></collection>
</resultMap>
<resultMap id="RoleMap" type="com.example.demo.model.Role">
<id column="id" property="id" jdbcType="INTEGER"></id>
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
<collection property="permissions" javaType="java.util.Set" column="id" select="selectAllPermissions"></collection>
</resultMap>
<select id="selectRoles" resultMap="RoleMap" parameterType="java.lang.Integer">
select *
from role
where id in (select user_role.role_id from user_role where user_id = #{id})
</select>
<select id="selectAllPermissions" resultType="com.example.demo.model.Permission" parameterType="java.lang.Integer">
select id,permission_name as permissionsName
from permission
where id in (select permission_id from role_permission where role_id = #{id})
</select>
<select id="getUserByName" resultMap="UserMap" parameterType="java.lang.String">
select *
from user
where user_name = #{userName}
</select>
</mapper>
数据库表结构截图
user 表 ---用户信息表
role 表 --- 角色表
permission 表 ---权限表
user_role 表
role_permission 表
打断点调试为
七、SpringBoot 将mybatis缓存到redis中
每次校验权限都会调用mybatis查询数据库,可以将查询结果缓存到redis中
配置如下
pom.xml 文件中增加
<!--redis整合springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
RedisConfig.class
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@EnableCaching
@Configuration
public class RedisConfig {
private Duration timeToLive = Duration.ofHours(1);
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(timeToLive)
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
查询接口使用@Cacheable进行缓存
@Cacheable(value = "user")
@Override
public User getUserByName(String userName) {
// return getMapByName(userName);
return loginMapper.getUserByName(userName);
}
访问接口后redis中存储如下数据
shiro 部分基本完成,再发现什么后边补