[踩坑]使用shiro-redis插件退出登录报缺少id的错

解决Shiro-Redis中因未正确配置principalIdFieldName而导致的PrincipalInstanceException错误。通过设置cacheManager.principalIdFieldName为实际ID字段名,确保唯一标识符正确获取。

在使用shiro-redis的时候报了这个错误:

org.crazycake.shiro.exception.PrincipalInstanceException: class com.baskbull.library_system.shiro.vo.AccountProfile must has getter for field: id
We need a field to identify this Cache Object in Redis. So you need to defined an id field which you can get unique id to identify this principal. For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. For example, getUserId(), getUserName(), getEmail(), etc.
Default value is "id", that means your principal object has a method called "getId()"
	at org.crazycake.shiro.RedisCache.getPrincipalIdGetter(RedisCache.java:193) ~[shiro-redis-3.3.1.jar:na]
	at org.crazycake.shiro.RedisCache.getRedisKeyFromPrincipalIdField(RedisCache.java:167) ~[shiro-redis-3.3.1.jar:na]
	at org.crazycake.shiro.RedisCache.getStringRedisKey(RedisCache.java:150) ~[shiro-redis-3.3.1.jar:na]
	at org.crazycake.shiro.RedisCache.getRedisCacheKey(RedisCache.java:137) ~[shiro-redis-3.3.1.jar:na]
	at org.crazycake.shiro.RedisCache.remove(RedisCache.java:117) ~[shiro-redis-3.3.1.jar:na]
	at org.apache.shiro.realm.AuthorizingRealm.clearCachedAuthorizationInfo(AuthorizingRealm.java:387) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.realm.AuthorizingRealm.doClearCache(AuthorizingRealm.java:666) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.realm.CachingRealm.clearCache(CachingRealm.java:170) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.realm.CachingRealm.onLogout(CachingRealm.java:152) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.onLogout(ModularRealmAuthenticator.java:296) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.mgt.DefaultSecurityManager.logout(DefaultSecurityManager.java:563) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.subject.support.DelegatingSubject.logout(DelegatingSubject.java:367) ~[shiro-core-1.6.0.jar:1.6.0]
	at com.baskbull.library_system.controller.AccountController.logout(AccountController.java:55) ~[classes/:na]
	at com.baskbull.library_system.controller.AccountController$$FastClassBySpringCGLIB$$8570185b.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.1.jar:5.3.1]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.3.1.jar:5.3.1]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.1.jar:5.3.1]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.1.jar:5.3.1]
	at org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor$1.proceed(AopAllianceAnnotationsAuthorizingMethodInterceptor.java:82) ~[shiro-spring-1.6.0.jar:1.6.0]
	at org.apache.shiro.authz.aop.AuthorizingMethodInterceptor.invoke(AuthorizingMethodInterceptor.java:39) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor.invoke(AopAllianceAnnotationsAuthorizingMethodInterceptor.java:115) ~[shiro-spring-1.6.0.jar:1.6.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.1.jar:5.3.1]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.1.jar:5.3.1]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.3.1.jar:5.3.1]
	at com.baskbull.library_system.controller.AccountController$$EnhancerBySpringCGLIB$$abfe3fe0.logout(<generated>) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.1.jar:5.3.1]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:807) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.1.jar:5.3.1]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:112) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:450) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387) ~[shiro-core-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) ~[shiro-web-1.6.0.jar:1.6.0]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.1.jar:5.3.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.1.jar:5.3.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.1.jar:5.3.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.1.jar:5.3.1]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at java.base/java.lang.Thread.run(Thread.java:830) ~[na:na]

2020-12-10 14:02:40.852  WARN 21316 --- [nio-8081-exec-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.crazycake.shiro.exception.PrincipalInstanceException: class com.baskbull.library_system.shiro.vo.AccountProfile must has getter for field: id
We need a field to identify this Cache Object in Redis. So you need to defined an id field which you can get unique id to identify this principal. For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. For example, getUserId(), getUserName(), getEmail(), etc.
Default value is "id", that means your principal object has a method called "getId()"]

报这个错误的原因是我的用户名使用的不是id导致的,查阅作者的文档:
shiro-redis使用文档
可以看到我们需要配置
cacheManager.principalIdFieldName = 你设置的id
在网上查到的方法都不管用 我自己找了个地方设置 可以把principalIdFiledName设置在这里:
在这里插入图片描述
然后在退出的时候就不会报错啦!

本项目详细介绍请看:http://www.sojson.com/shiro (强烈推荐) Demo已经部署到线上,地址是http://shiro.itboy.net, 管理员帐号:admin,密码:sojson.com 如果密码误,请用sojson。 PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快,有问题加群解决。 声明: 本人提供这个Shiro + SpringMvc + Mybatis + Redis 的Demo 本着学习的态度,如果有欠缺和不足的地方,给予指正,并且多多包涵。 “去其糟粕取其精华”。如果觉得写的好的地方就给个赞,写的不好的地方,也请多多包涵。 使用过程: 1.创建数据库。 创建语句 :tables.sql 2.插入初始化数据 插入初始化数据:init.data.sql 3.运行。 管理员帐号:admin 密码:sojson ps:定时任务的sql会把密码改变为sojson.com 新版本说明:http://www.sojson.com/blog/164.html 和 http://www.sojson.com/blog/165.html 主要解决是之前说的问题:Shiro 教程,关于最近反应的相关异常问题,解决方法合集。 项目在本页面的附件中提取。 一、Cache配置修改。 配置文件(spring-cache.xml )中已经修改为如下配置: <!-- redis 配置,也可以把配置挪到properties配置文件中,再读取 --> <!-- 这种 arguments 构造的方式,之前配置有缺点。 这里之前的配置有问题,因为参数类型不一致,有时候jar和环境的问题,导致参数根据index对应,会处理问题, 理论上加另一个 name,就可以解决,现在把name 和type都加上,更保险。 --> 二、登录获取上一个URL地址。 当没有获取到退出前的request ,为null 的时候会。在(UserLoginController.java )135行处有所修改。 /** * shiro 获取登录之前的地址 * 之前0.1版本这个没判断空。 */ SavedRequest savedRequest = WebUtils.getSavedRequest(request); String url = null ; if(null != savedRequest){ url = savedRequest.getRequestUrl(); } /** * 我们平常用的获取上一个请求的方式,在Session不一致的情况下是获取不到的 * String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE); */ 三、删除了配置文件中的cookie写入域的问题。 在配置文件里(spring-shiro.xml )中的配置有所修改。 <!-- 会话Cookie模板 --> <!--cookie的name,我故意取名叫xxxxbaidu --> <!--cookie的有效时间 --> <!-- 配置存储Session Cookie的domain为 一级域名 --> 上面配置是去掉了 Session 的存储Key 的作用域,之前设置的.itboy.net ,是写到当前域名的 一级域名 下,这样就可以做到N 个 二级域名 下,三级、四级....下 Session 都是共享的。 <!-- 用户信息记住我功能的相关配置 --> <!-- 配置存储rememberMe Cookie的domain为 一级域名 --> <!-- 30天时间,记住我30天 --> 记住我登录的信息配置。和上面配置是一样的道理,可以在相同 一级域名 下的所有域名都可以获取到登录的信息。 四、简单实现了单个帐号只能在一处登录。 我们在其他的系统中可以看到,单个帐号只允许一人使用,在A处登录了,B处再登录,那A处就被踢出了。如下图所示。 但是此功能不是很完美,当A处被踢出后,再重新登录,这时候B处反应有点慢,具体我还没看,因为是之前加的功能,现在凌晨了,下次我有空再瞧瞧,同学你也可以看看,解决了和我说一声,我把功能修复。 五、修复功能(BUG) 1.修复权限添加功能BUG。 之前功能有问题,每当添加一个权限的时候,默认都给角色为“管理员”的角色默认添加当前新添加的权限。这样达到管理员的权限永远是最大的。由于代码有BUG ,导致所有权限删除了。现已修复。 2.修复项目只能部署到Root目录下的问题。 问题描述:之前项目只能部署到Root 下才能正常运行,目前已经修复,可以带项目路径进行访问了,之前只能这样访问,http://localhost:8080 而不能http://localhost:8080/shiro.demo/ 访问,目前是可以了。 解决方案:在 FreeMarkerViewExtend.java 33行处 增加了BasePath ,通过BasePath 来控制请求目录,在 Freemarker 中可以自由使用,而 JSP 中是直接在 JSP 中获取BasePath 使用。 解决后遗症:因为我们的权限是通过URL 来控制的,那么增加了项目的目录,导致权限不能正确的判断,再加上我们的项目名称(目录)可以自定义,导致更不好判断。 后遗症解决方案:PermissionFilter.java 50行处 解决了这个问题,详情请看代码和注释,其实就是replace 了一下。 HttpServletRequest httpRequest = ((HttpServletRequest)request); /** * 此处是改版后,为了兼容项目不需要部署到root下,也可以正常运行,但是权限没设置目前必须到root 的URI, * 原因:如果你把这个项目叫 ShiroDemo,那么路径就是 /ShiroDemo/xxxx.shtml ,那另外一个人使用,又叫Shiro_Demo,那么就要这么控制/Shiro_Demo/xxxx.shtml * 理解了吗? * 所以这里替换了一下,使用根目录开始的URI */ String uri = httpRequest.getRequestURI();//获取URI String basePath = httpRequest.getContextPath();//获取basePath if(null != uri && uri.startsWith(basePath)){ uri = uri.replace(basePath, ""); } 3.项目启动的时候,关于JNDI的误提示。 其实也不是,但是看着不舒服,所以还得解决这个问题。解决这个问题需要在web.xml 中的开始部位加入以下代码。 spring.profiles.active dev spring.profiles.default dev spring.liveBeansView.mbeanDomain dev 4.项目Maven打包问题。 打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码(群里同学提供的)。 src/main/java **/*.properties **/*.xml false 在 标签内加入即可,如果还是不能解决,那么请你加群(改名后)说明你的问题,有人会回答你。 5.Tomcat7以上在访问JSP页面的时候,提示JSTL误。 这个误是因为Tomcat7 中没有 JSTL 的jar包,现在已经在项目pom.xml 中增加了如下 jar 的引入管理。 javax.servlet jstl 1.2 javax.servlet jsp-api 2.0 provided 如果还是不能解决问题,请在官方群(群号:259217951)内搜索“jstl” 如图下载依赖包。
### Shiro-Redis使用 JSON 序列化的配置 在 ShiroRedis 的集成过程中,为了提高数据可读性和兼容性,通常会选择使用 JSON 格式的序列化方式。以下是关于如何在 Shiro-Redis 中配置 JSON 序列化的详细说明。 #### 1. 添加依赖 首先,在项目中引入必要的依赖库。这里主要涉及 `shiro-spring`、`shiro-redis` 和 `fastjson` 或者其他 JSON 处理工具包。 ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.1</version> </dependency> <!-- shiro-redis --> <dependency> <groupId>com.github.marcosbarbero</groupId> <artifactId>spring-boot-starter-shiro-redis</artifactId> <version>2.7.0</version> </dependency> <!-- fastjson for serialization --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> ``` 以上代码片段展示了 Maven 构建文件中的必要依赖项[^1]。 #### 2. 自定义缓存管理器 通过扩展 `ShiroCacheManager` 来实现自定义的缓存管理逻辑,并设置 JSON 序列化机制。 ```java import com.alibaba.fastjson.JSON; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.spring.boot.autoconfigure.ShiroProperties; import org.springframework.data.redis.core.RedisTemplate; public class JsonSerializationRedisCache<K, V> implements Cache<K, V> { private final RedisTemplate<String, String> redisTemplate; private final String cacheName; public JsonSerializationRedisCache(RedisTemplate<String, String> redisTemplate, String cacheName) { this.redisTemplate = redisTemplate; this.cacheName = cacheName; } @Override public V get(K key) throws CacheException { String serializedKey = serializeKey(key); String value = redisTemplate.opsForValue().get(serializedKey); return deserializeValue(value); } @Override public V put(K key, V value) throws CacheException { String serializedKey = serializeKey(key); String serializedValue = serializeValue(value); redisTemplate.opsForValue().set(serializedKey, serializedValue); return value; } @Override public V remove(K key) throws CacheException { String serializedKey = serializeKey(key); String oldValue = redisTemplate.opsForValue().get(serializedKey); redisTemplate.delete(serializedKey); return deserializeValue(oldValue); } @Override public void clear() throws CacheException { redisTemplate.delete(redisTemplate.keys(cacheName + "*")); } @Override public int size() { return (int) redisTemplate.keys(cacheName + "*").size(); } @Override public Set<K> keys() { return redisTemplate.keys(cacheName + "*").stream() .map(this::deserializeKey) .collect(Collectors.toSet()); } @Override public Collection<V> values() { return redisTemplate.values(cacheName + "*").stream() .map(this::deserializeValue) .collect(Collectors.toList()); } private String serializeKey(K key) { return cacheName + ":" + JSON.toJSONString(key); } private K deserializeKey(String serializedKey) { return JSON.parseObject(serializedKey.replace(cacheName + ":", ""), (Class<K>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]); } private String serializeValue(V value) { return JSON.toJSONString(value); } private V deserializeValue(String serializedValue) { if (serializedValue == null) { return null; } return JSON.parseObject(serializedValue, (Class<V>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1]); } } ``` 此部分实现了基于 JSON 的键值对序列化与反序列化功能[^2]。 #### 3. 配置 Bean 注入 最后一步是在 Spring Boot 的配置类中注入并启用该自定义缓存管理器。 ```java @Configuration @EnableConfigurationProperties(ShiroProperties.class) public class ShiroConfig { @Bean public CacheManager cacheManager(RedisTemplate<String, String> redisTemplate) { return new JsonSerializationRedisCache<>(redisTemplate, "shiro-cache"); } @Bean public SecurityManager securityManager(CacheManager cacheManager) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setCacheManager(cacheManager); return manager; } } ``` 上述代码完成了将 JSON 序列化应用到 Shiro 缓存的具体操作[^3]。 --- ###
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值