日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot整合shiro-关于登出时,redis中缓存没有清理干净的问题

發布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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());

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//獲取用戶名密碼 第一種方式//String username = (String) authenticationToken.getPrincipal();//String password = new String((char[]) authenticationToken.getCredentials());//獲取用戶名 密碼 第二種方式UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;String username = usernamePasswordToken.getUsername();String password = new String(usernamePasswordToken.getPassword());//從數據庫查詢用戶信息User user = this.userMapper.findByUserName(username);//可以在這里直接對用戶名校驗,或者調用 CredentialsMatcher 校驗if (user == null) {throw new UnknownAccountException("用戶名或密碼錯誤!");}//這里將 密碼對比 注銷掉,否則 無法鎖定 要將密碼對比 交給 密碼比較器//if (!password.equals(user.getPassword())) {// throw new IncorrectCredentialsException("用戶名或密碼錯誤!");//}if ("1".equals(user.getState())) {throw new LockedAccountException("賬號已被鎖定,請聯系管理員!");}SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),new MyByteSource(user.getUsername()),getName());return info; }

并且修改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用戶的權限緩存。

/*** 將該權限賦給 admin用戶 使用admin用戶清理其他用戶的 權限緩存* @param username* @return*/ @RequiresPermissions("userInfo:clearCache") @RequestMapping(value = "/clearCache",method = RequestMethod.GET) @ResponseBody public String clearCache(String username) {String[] keys = new String[3];keys[0] = "shiro:cache:authenticationCache:"+username;keys[1] = "shiro:cache:authorizationCache:"+username;keys[2] = "shiro:cache:retrylimit:"+username;//原子性 命令 刪除多個keyshiroRedisTemplate.delete(CollectionUtils.arrayToList(keys));return "刪除"+username+"權限成功";}

網友給出的更簡潔方案:在自定義的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中缓存没有清理干净的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。