在線會話管理

有時候須要顯示當前在線人數、當前在線用戶,有時候可能須要強制某個用戶下線等;此時就須要獲取相應的在線用戶並進行一些操做。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  

相關文章
相關標籤/搜索