1、自定義訪問(wèn)控制攔截器曹步,繼承AccessControlFilter宪彩,實(shí)現(xiàn)以下三個(gè)方法。
abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;
boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;
abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;
2讲婚、自定義BeamUserFilter
public class GunsUserFilter extends AccessControlFilter {
private String kickoutUrl; //踢出后到的地址
private boolean kickoutAfter = false; //踢出之前登錄的/之后登錄的用戶 默認(rèn)踢出之前登錄的用戶
private int maxSession = 1; //同一個(gè)帳號(hào)最大會(huì)話數(shù) 默認(rèn)1
private org.apache.shiro.cache.Cache<String, Deque<Serializable>> cache;
public void setKickoutUrl(String kickoutUrl) {
this.kickoutUrl = kickoutUrl;
}
public void setKickoutAfter(boolean kickoutAfter) {
this.kickoutAfter = kickoutAfter;
}
public void setMaxSession(int maxSession) {
this.maxSession = maxSession;
}
//設(shè)置Cache的key的前綴
public void setCacheManager(CacheManager cacheManager) {
this.cache = cacheManager.getCache("shiro_redis_cache");
}
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return false;
/*if (isLoginRequest(request, response)) {
return true;
} else {
Subject subject = getSubject(request, response);
// If principal is not null, then the user is known and should be allowed access.
return subject.getPrincipal() != null;
}*/
}
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
/**
* 如果是ajax請(qǐng)求則不進(jìn)行跳轉(zhuǎn)
*/
if (httpServletRequest.getHeader("x-requested-with") != null
&& httpServletRequest.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
httpServletResponse.setHeader("sessionstatus", "timeout");
return false;
} else {
/*-----------------單機(jī)用戶唯一登陸------------------------------*/
/**
*
* @date 創(chuàng)建時(shí)間:2018年3月27日
* 1.讀取當(dāng)前登錄用戶名尿孔,獲取在緩存中的sessionId隊(duì)列
* 2.判斷隊(duì)列的長(zhǎng)度,大于最大登錄限制的時(shí)候筹麸,按踢出規(guī)則
* 將之前的sessionId中的session域中存入kickout:true活合,并更新隊(duì)列緩存
* 3.判斷當(dāng)前登錄的session域中的kickout如果為true,
* 想將其做退出登錄處理物赶,然后再重定向到踢出登錄提示頁(yè)面
*/
Subject subject = getSubject(request, response);
if(!subject.isAuthenticated() && !subject.isRemembered()) {
//如果沒(méi)有登錄白指,直接進(jìn)行之后的流程
return true;
}
Session session = subject.getSession();
ShiroUser user = ShiroKit.getUser();
String username = user.getAccount();
Serializable sessionId = session.getId();
//讀取緩存 沒(méi)有就存入
Deque<Serializable> deque = cache.get(username);
//如果此用戶沒(méi)有session隊(duì)列,也就是還沒(méi)有登錄過(guò)酵紫,緩存中沒(méi)有
//就new一個(gè)空隊(duì)列告嘲,不然deque對(duì)象為空,會(huì)報(bào)空指針
if(deque==null){
deque = new LinkedList<Serializable>();
}
//如果隊(duì)列里沒(méi)有此sessionId奖地,且用戶沒(méi)有被踢出橄唬;放入隊(duì)列
if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
//將sessionId存入隊(duì)列
deque.push(sessionId);
//將用戶的sessionId隊(duì)列緩存
cache.put(username, deque);
}
//如果隊(duì)列里的sessionId數(shù)超出最大會(huì)話數(shù),開始踢人
while(deque.size() > maxSession) {
Serializable kickoutSessionId = null;
if(kickoutAfter) { //如果踢出后者
kickoutSessionId = deque.removeFirst();
//踢出后再更新下緩存隊(duì)列
cache.put(username, deque);
} else { //否則踢出前者
kickoutSessionId = deque.removeLast();
//踢出后再更新下緩存隊(duì)列
cache.put(username, deque);
}
try {
//獲取被踢出的sessionId的session對(duì)象
Session kickoutSession = SecurityUtils.getSecurityManager().getSession(new DefaultSessionKey(kickoutSessionId));
if(kickoutSession != null) {
//設(shè)置會(huì)話的kickout屬性表示踢出了
kickoutSession.setAttribute("kickout", true);
}
} catch (Exception e) {//ignore exception
}
}
//如果被踢出了参歹,直接退出仰楚,重定向到踢出后的地址
if ((Boolean)session.getAttribute("kickout")!=null&&(Boolean)session.getAttribute("kickout") == true) {
System.out.println("被踢出");
//會(huì)話被踢出了
try {
//退出登錄
subject.logout();
} catch (Exception e) { //ignore
}
saveRequest(request);
//重定向
WebUtils.issueRedirect(request, response, kickoutUrl);
return false;
}
return true;
/*--------------------------------------------------------*/
/**
* 第一次點(diǎn)擊頁(yè)面
*/
/*String referer = httpServletRequest.getHeader("Referer");
if (referer == null) {
System.out.println("進(jìn)來(lái)7");
redirectToLogin(request, response);
return false;
} else {
System.out.println("進(jìn)來(lái)8");
//從別的頁(yè)面跳轉(zhuǎn)過(guò)來(lái)的
if (ShiroKit.getSession().getAttribute("sessionFlag") == null) {
System.out.println("進(jìn)來(lái)9");
httpServletRequest.setAttribute("tips", "session超時(shí)");
httpServletRequest.getRequestDispatcher("/login.html").forward(request, response);
return false;
} else {
System.out.println("進(jìn)來(lái)10");
redirectToLogin(request, response);
return false;
}
}*/
}
}
}
3、ShiroConfig配置犬庇,加入以下配置
/**
* 限制同一賬號(hào)登錄同時(shí)登錄人數(shù)控制
* @return
*/
@Bean
public BeamUserFilter beamUserFilter(){
BeamUserFilter beamUserFilter = new BeamUserFilter ();
//使用cacheManager獲取相應(yīng)的cache來(lái)緩存用戶登錄的會(huì)話僧界;用于保存用戶—會(huì)話之間的關(guān)系的;
//這里我們還是用之前shiro使用的redisManager()實(shí)現(xiàn)的cacheManager()緩存管理
//也可以重新另寫一個(gè)械筛,重新配置緩存時(shí)間之類的自定義緩存屬性
beamUserFilter .setCacheManager(getCacheShiroManager(new EhCacheManagerFactoryBean()));
beamUserFilter .setKickoutAfter(false);
//同一個(gè)用戶最大的會(huì)話數(shù)捎泻,默認(rèn)1;比如2的意思是同一個(gè)用戶允許最多同時(shí)兩個(gè)人登錄埋哟;
beamUserFilter .setMaxSession(1);
//被踢出后重定向到的地址笆豁;
beamUserFilter .setKickoutUrl("/login");
return beamUserFilter ;
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者