shiro 删除用户session_我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录)...
看了一下官網,沒有找到關于如何控制同一用戶只能一處登錄的介紹,網上也沒有找到相關的文章。可能有些人會記錄用戶的登錄信息,然后達到踢出用戶的效果。這里介紹一個更簡單的方法。
如果我們跟shiro的源碼,我們可以看到。當用戶登錄成功 后,shiro會把用戶名放到session的attribute中,key為 DefaultSubjectContext_PRINCIPALS_SESSION_KEY,這個key的定義是在shiro的 org.apache.shiro.subject.support.DefaultSubjectContext中,這個類有三個public的靜態屬 性,其他都為private。其中PRINCIPALS_SESSION_KEY這個屬性記錄的是用戶名,而 AUTHENTICATED_SESSION_KEY屬性記錄的是用戶認證,當用戶登錄成功后,這個attribute的值是true。
曾經我想把AUTHENTICATED_SESSION_KEY這個 attribute的值設置為false,表示用戶是退出狀態,這樣達到退出用戶的目的,不過沒有成功,shiro判斷用戶是否是登錄狀態并不從這里判 斷。不過既然我們可以通過用戶名可以找到用戶對應的session,也很容易將該session刪除,讓用戶重新建立一個新的sesison。這里給出一 個幫助類,帶有跳出用戶的功能。
package com.concom.security.infrastructure.helper;
import java.util.Collection;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.concom.lang.helper.TimeHelper;
import com.concom.security.application.memcache.CurrentUserMemcacheService;
import com.concom.security.application.user.UserService;
import com.concom.security.domain.user.User;
/**
* @author Dylan
* @time 2013-8-12
*/
public class ShiroSecurityHelper {
private final static Logger log = LoggerFactory.getLogger(ShiroSecurityHelper.class);
private static UserService userService;
private static CurrentUserMemcacheService currentUserMemcacheService;
private static SessionDAO sessionDAO;
/**
* 把user放到cache中
*
* @param user
*/
public static void setUser(User user) {
currentUserMemcacheService.save(user);
}
/**
* 清除當前用戶的緩存
*/
public static void clearCurrentUserCache() {
if (hasAuthenticated()) {
currentUserMemcacheService.remove(getCurrentUsername());
}
}
/**
* 從cache拿當前user
*
* @return
*/
public static User getCurrentUser() {
if (!hasAuthenticated()) {
return null;
}
User user = currentUserMemcacheService.get(getCurrentUsername());
try {
if (null == user) {
user = userService.getByUsername(getCurrentUsername());
ShiroSecurityHelper.setUser(user);
}
return user;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 獲得當前用戶名
*
* @return
*/
public static String getCurrentUsername() {
Subject subject = getSubject();
PrincipalCollection collection = subject.getPrincipals();
if (null != collection && !collection.isEmpty()) {
return (String) collection.iterator().next();
}
return null;
}
/**
*
* @return
*/
public static Session getSession() {
return SecurityUtils.getSubject().getSession();
}
/**
*
* @return
*/
public static String getSessionId() {
Session session = getSession();
if (null == session) {
return null;
}
return getSession().getId().toString();
}
/**
* @param username
* @return
*/
public static Session getSessionByUsername(String username){
Collection sessions = sessionDAO.getActiveSessions();
for(Session session : sessions){
if(null != session && StringUtils.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)), username)){
return session;
}
}
return null;
}
/**踢除用戶
* @param username
*/
public static void kickOutUser(String username){
Session session = getSessionByUsername(username);
if(null != session && !StringUtils.equals(String.valueOf(session.getId()), ShiroSecurityHelper.getSessionId())){
ShiroAuthorizationHelper.clearAuthenticationInfo(session.getId());
log.info("############## success kick out user 【{}】 ------ {} #################", username,TimeHelper.getCurrentTime());
}
}
/**
* @param userService
* @param currentUserMemcacheService
* @param sessionDAO
*/
public static void initStaticField(UserService userService,CurrentUserMemcacheService currentUserMemcacheService,SessionDAO sessionDAO){
ShiroSecurityHelper.userService = userService;
ShiroSecurityHelper.currentUserMemcacheService = currentUserMemcacheService;
ShiroSecurityHelper.sessionDAO = sessionDAO;
}
/**
* 判斷當前用戶是否已通過認證
* @return
*/
public static boolean hasAuthenticated() {
return getSubject().isAuthenticated();
}
private static Subject getSubject() {
return SecurityUtils.getSubject();
}
}
再通過spring注入幫助類需要的靜態屬性。
讀者可以不關注userService,currentUserMemcacheService,其中踢出功能用到了SessionDAO,定義可能看我的shiro之旅: 七 shiro session 共享,文章里的spring配置文件有介紹,這里不再作描述。從這個類名我們就可以猜想到,這個類是用戶管理session的。ShiroAuthorizationHelper這個幫助類在我的shiro之旅:
九 shiro 清理緩存的權限信息這篇文章介紹到。通過用戶名使用用戶對應的session,然后將該session刪除,這個kickOutUser方法應該在用戶登錄之前調用。
session刪除后,當用戶再請求服務器時,服務端shiro會拋
出there is no
session的異常,然后從新為請求建立一個新的session,就像用戶很長時間沒有點擊瀏覽器,shiro的定時器定時將失效的session清除
的時候也拋出這個異常一樣。不過這個對用戶是透明的,對用戶的體驗沒有影響。
這是其中的一種方式,也許有更好的實現方式。如果讀者有更好的實現方式,希望能與我分享。
總結
以上是生活随笔為你收集整理的shiro 删除用户session_我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 80070583类不存在_原创 | 类应
- 下一篇: bootcamp空间不足_Bootcam