springboot整合shiro-关于登出时,redis中缓存没有清理干净的问题
原文地址,轉載請注明出處: https://blog.csdn.net/qq_34021712/article/details/84722724 ?王賽超
如果是跟著我的shiro系列博客敲下來的,其實還有一個bug,這是一個網友遇到的,他在登出的時候,發現redis中當前用戶身份認證緩存沒有清理掉,之前在 springboot整合shiro-ehcache緩存(五) 中測試添加權限之后,清理的是所有用戶的緩存,所以沒有發現這個問題。
還記得上一篇博客: springboot整合shiro-實現自己登出(十五), 我們在登出方法中,清理了當前用戶的 身份認證 和 權限認證的 緩存信息,最后發現有一個key 沒有清理掉,如下圖:
為什么 該key沒有清除掉呢?經過debug發現,在清理 身份認證 緩存的時候,調用了ShiroRealm的clearCachedAuthenticationInfo 最終調用到 RedisCache的 remove 方法,但是傳過來key 卻是 User實體,為什么會是User實體,就是因為在 ShiroRealm 的 doGetAuthenticationInfo 方法返回值 SimpleAuthenticationInfo 中,第一個參數 傳的是 User實體,具體 debug細節 如下:
而在刪除 用戶 權限緩存時,卻沒有這個問題,刪除緩存時,傳入的key為SimplePrincipalCollection 最終調用getRedisKeyFromPrincipalIdField 根據你在 ShiroConfig中 配置 RedisCacheManager 指定的那個字段作為緩存的前綴,根據反射獲取該字段的值 并返回,具體的配置信息,可以參考之前博客的源碼:
解決方案
第一種,判斷key為User實體,強轉并獲取用戶名
第二種,將ShiroRealm 的 doGetAuthenticationInfo 方法返回值 SimpleAuthenticationInfo 中,第一個參數,傳username,不要傳User實體
第一步:修改ShiroRealm
修改shiroRealm中的 doGetAuthenticationInfo 驗證用戶身份的最后一句 返回值
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),new MyByteSource(user.getUsername()),getName());
并且修改shiroRealm中 的 doGetAuthorizationInfo 方法,SecurityUtils.getSubject().getPrincipal()之前 返回的是User實體,現在 就是我們上一步中 放進去的用戶名。并且這里需要再單獨根據 username去數據庫查詢 User
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("查詢權限方法調用了!!!");//這里獲取到的就是 上面方法放進去的username了String username = (String)SecurityUtils.getSubject().getPrincipal();//需要單獨根據 username 從數據庫查詢用戶信息User user = this.userMapper.findByUserName(username);//獲取用戶角色Set<Role> roles =this.roleMapper.findRolesByUserId(user.getUid());//添加角色SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();for (Role role : roles) {authorizationInfo.addRole(role.getRole());}//獲取用戶權限Set<Permission> permissions = this.permissionMapper.findPermissionsByRoleId(roles);//添加權限for (Permission permission:permissions) {authorizationInfo.addStringPermission(permission.getPermission());}return authorizationInfo; }第二步:修改項目中 其他地方 使用 (User)SecurityUtils.getSubject().getPrincipal();的 代碼
因為 我們在第一部中 已經將 Principal 從 User實體 改為了 username 所以這些相應的都需要修改,這里要看你們代碼中都是在那里使用的了。
第三步:修改之前 index.html頁面中的34行 <shiro:principal property=“username”/>
因為 principal為 用戶名,已經不是實體了,這里再指定 property 就會報如下 異常:
2018/11/30 15:13:28.861 org.thymeleaf.TemplateEngine [] ERROR [THYMELEAF][http-nio-9090-exec-5] Exception processing template "index": Error during execution of processor 'at.pollux.thymeleaf.shiro.processor.element.HasPermissionElementProcessor' (index:15) 2018/11/30 15:13:28.862 o.s.web.servlet.DispatcherServlet [] DEBUG Error rendering view [org.thymeleaf.spring4.view.ThymeleafView@7578de10] in DispatcherServlet with name 'dispatcherServlet' org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'at.pollux.thymeleaf.shiro.processor.element.HasPermissionElementProcessor' (index:15)具體如下圖,只需要使用 shiro:principal</shiro:principal> 就可以了。
第四步:修改RedisCache 類中的 getStringRedisKey 方法
直接返回 key.toString 下面的 getRedisKeyFromPrincipalIdField方法 也可以直接刪除了,因為不再使用它了 ,原本 它存在的意義 就是為了解決 principal放的是 User實體。
第五步:啟動測試
將redis清空, 并將瀏覽器緩存清除,啟動項目測試,問題已解決,至于另外兩個key都是我們自定義的功能,如果想要刪除的話,直接刪除redis的key就行了 都是使用username 拼接的key。
管理員清理其他用戶的緩存
還有這樣一種情況,有test 和 admin兩名用戶, admin是管理員,在給 test用戶分配新的權限之后,需要清除該用戶的 權限緩存信息 ,這里有一種笨方法,如下 ,添加一個 刪除用戶緩存的方法, 只有 userInfo:clearCache 權限才可以執行此操作 ,并將 該權限給admin用戶,在admin用戶 給test用戶 分配新的權限之后,可以立即清除test用戶的權限緩存。
網友給出的更簡潔方案:在自定義的Realm中重寫下面這兩個方法。
/*** 建議重寫此方法,提供唯一的緩存Key*/@Overrideprotected Object getAuthorizationCacheKey(PrincipalCollection principals) {UserInfoDO user = (UserInfoDO) principals.getPrimaryPrincipal();return user.getUserName(); // return super.getAuthorizationCacheKey(principals);}/*** 建議重寫此方法,提供唯一的緩存Key*/@SuppressWarnings("unchecked")@Overrideprotected Object getAuthenticationCacheKey(PrincipalCollection principals) {UserInfoDO user = (UserInfoDO) principals.getPrimaryPrincipal();return user.getUserName(); // return super.getAuthenticationCacheKey(principals);}總結
以上是生活随笔為你收集整理的springboot整合shiro-关于登出时,redis中缓存没有清理干净的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决layui数据表格table固定列行
- 下一篇: Easyexcel文件下载时,中文名称显