如下,找到session中的信息刪除即可,按照這個方式試了下。基本可用
在多台服務器部署時,前提必須實現session共享。
/**
* 登錄認證
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//獲取用戶的輸入的賬號.
String username = (String)token.getPrincipal();
//通過username從數據庫中查找 User對象,如果找到,沒找到.
//實際項目中,這里可以根據實際情況做緩存,如果不做,Shiro自己也是有時間間隔機制,2分鍾內不會重復執行該方法
LoginUser userInfo = loginUserBiz.getByName(username);
if(null==userInfo){
return null;
}
//2.處理一個賬號異地登錄的問題,后期用戶量上來需要做優化,比如登錄用cas
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
//獲取當前已登錄的用戶session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
for(Session session:sessions){
//查找是否有當前登錄賬戶的記錄,有就清除該用戶以前登錄時保存的session
Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if(null!=obj){
if(obj instanceof SimplePrincipalCollection){
//強轉
SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
LoginUser user = new LoginUser();
BeanUtils.copyProperties(spc.getPrimaryPrincipal(),user);
//判斷用戶,匹配用戶ID。
if(userInfo.getId().equals(user.getId())){
sessionManager.getSessionDAO().delete(session);
}
}
}
}
//創建認證
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用戶信息
userInfo.getPassword(), //密碼
ByteSource.Util.bytes(userInfo.getSalt()),//passsword=MD5(pass+salt)
getName() //realm name
);
return authenticationInfo;
}
DEBUG信息如下,也可以把比對的對象轉換后在比對登錄id
可以看到上面的代碼是找到登錄的賬號,刪除了其session,然后重新創建認證。
當然我們不重寫shiro的登錄認證方法,在業務層也是可以實現的。首先查詢當前登錄賬號是否存在,存在直接調用SecurityUtils.getSubject().logout()退出登錄,然后再調用一次登錄,只是這樣更復雜而已。