有時候須要顯示當前在線人數、當前在線用戶,有時候可能須要強制某個用戶下線等;此時就須要獲取相應的在線用戶並進行一些操做。java
會話控制器git
@RequiresPermissions("session:*") @Controller @RequestMapping("/sessions") public class SessionController { @Autowired private SessionDAO sessionDAO; @RequestMapping() public String list(Model model) { Collection<Session> sessions = sessionDAO.getActiveSessions(); model.addAttribute("sessions", sessions); model.addAttribute("sesessionCount", sessions.size()); return "sessions/list"; } @RequestMapping("/{sessionId}/forceLogout") public String forceLogout(@PathVariable("sessionId") String sessionId, RedirectAttributes redirectAttributes) { try { Session session = sessionDAO.readSession(sessionId); if(session != null) { session.setAttribute( Constants.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE); } } catch (Exception e) {/*ignore*/} redirectAttributes.addFlashAttribute("msg", "強制退出成功!"); return "redirect:/sessions"; } }
一、list方法:提供了展現全部在線會話列表,經過sessionDAO.getActiveSessions()獲取全部在線的會話。github
二、forceLogout方法:強制退出某一個會話,此處只在指定會話中設置Constants.SESSION_FORCE_LOGOUT_KEY屬性,以後經過ForceLogoutFilter判斷並進行強制退出。web
此處展現會話列表的缺點是:sessionDAO.getActiveSessions()提供了獲取全部活躍會話集合,若是作通常企業級應用問題不大,由於在線用戶很少;可是若是應用的在線用戶很是多,此種方法就不適合了,解決方案就是分頁獲取: redis
Page<Session> getActiveSessions(int pageNumber, int pageSize);
Page對象除了包含pageNumber、pageSize屬性以外,還包含totalSessions(總會話數)、Collection<Session> (當前頁的會話)。spring
分頁獲取時,若是是MySQL這種關係數據庫存儲會話比較好辦,若是使用Redis這種數據庫能夠考慮這樣存儲:數據庫
session.id=會話序列化數據 session.ids=會話id Set列表(接着可使用LLEN獲取長度,LRANGE分頁獲取)
會話建立時(如sessionId=123),那麼redis命令以下所示: session
SET session.123 "Session序列化數據" LPUSH session.ids 123
會話刪除時(如sessionId=123),那麼redis命令以下所示: app
DEL session.123 LREM session.ids 123
獲取總活躍會話:測試
LLEN session.ids
分頁獲取活躍會話:
LRANGE key 0 10 #獲取到會話ID MGET session.1 session.2…… #根據第一條命令獲取的會話ID獲取會話數據
ForceLogoutFilter
public class ForceLogoutFilter extends AccessControlFilter { protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { Session session = getSubject(request, response).getSession(false); if(session == null) { return true; } return session.getAttribute(Constants.SESSION_FORCE_LOGOUT_KEY) == null; } protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { try { getSubject(request, response).logout();//強制退出 } catch (Exception e) {/*ignore exception*/} String loginUrl = getLoginUrl() + (getLoginUrl().contains("?") ? "&" : "?") + "forceLogout=1"; WebUtils.issueRedirect(request, response, loginUrl); return false; } }
強制退出攔截器,若是用戶會話中存在Constants.SESSION_FORCE_LOGOUT_KEY屬性,表示被管理員強制退出了;而後調用Subject.logout()退出,且重定向到登陸頁面(自動拼上fourceLogout請求參數)。
登陸控制器
在LoginController類的showLoginForm方法中最後添加以下代碼:
if(req.getParameter("forceLogout") != null) { model.addAttribute("error", "您已經被管理員強制退出,請從新登陸"); }
即若是有請求參數forceLogout表示是管理員強制退出的,在界面上顯示相應的信息。
Shiro配置spring-config-shiro.xml
和以前的惟一區別是在shiroFilter中的filterChainDefinitions攔截器鏈定義中添加了forceLogout攔截器:
/** = forceLogout,user,sysUser
測試
一、首先輸入http://localhost:8080/chapter24/跳轉到登陸頁面輸入admin/123456登陸;
二、登陸成功後,點擊菜單的「會話管理」,能夠看到當前在線會話列表:
三、點擊「強制退出」按鈕,會話相應的用戶再點擊界面的話會看到以下界面,表示已經被強制退出了:
另外可參考個人ES中的在線會話管理功能:UserOnlineController.java,其使用數據庫存儲會話,並分頁獲取在線會話。
示例源代碼:https://github.com/zhangkaitao/shiro-example;
轉載自----------------http://jinnianshilongnian.iteye.com/blog/2047643