国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Shiro 控制并發登錄人數限制及登錄踢出的實現代碼

Shiro 控制并發登錄人數限制及登錄踢出的實現代碼

2021-01-06 11:18AinUser Java教程

本文通過shiro實現一個賬號只能同時一個人使用,本文重點給大家分享Shiro 控制并發登錄人數限制及登錄踢出的實現代碼,需要的朋友參考下吧

我們經常會有用到,當A 用戶在北京登錄 ,然后A用戶在天津再登錄 ,要踢出北京登錄的狀態。如果用戶在北京重新登錄,那么又要踢出天津的用戶,這樣反復。

這樣保證了一個帳號只能同時一個人使用。那么下面來講解一下 Shiro  怎么實現這個功能,現在是用到了緩存 Redis  。我們也可以用其他緩存。如果是單個點,直接用一個靜態的Map<String,Object> 或者 Ehcache  即可。

XML配置。

?
1
2
3
4
5
6
7
8
9
<!-- session 校驗單個用戶是否多次登錄 -->
<bean id="kickoutSessionFilter"  class="com.sojson.core.shiro.filter.KickoutSessionFilter">
  <property name="kickoutUrl" value="/u/login.shtml?kickout"/>
</bean>
<!-- 靜態注入 jedisShiroSessionRepository-->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="staticMethod" value="com.sojson.core.shiro.filter.KickoutSessionFilter.setShiroSessionRepository"/>
  <property name="arguments" ref="jedisShiroSessionRepository"/>
</bean>

 這里用到了靜態注入。如果不了解請看這篇:Spring 靜態注入講解(MethodInvokingFactoryBean)

加入到 shiro  的Filter 攔截序列

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 <property name="securityManager" ref="securityManager" />
 <property name="loginUrl" value="/u/login.shtml" />
 <!-- TODO 待提取 -->
<property name="successUrl" value="/" />
<property name="unauthorizedUrl" value="/?login" />
  <property name="filterChainDefinitions" value="#{shiroManager.loadFilterChainDefinitions()}"/> 
  <property name="filters">
    <util:map>
      <entry key="login" value-ref="login"></entry>
      <entry key="role" value-ref="role"></entry>
      <entry key="simple" value-ref="simple"></entry>
      <entry key="permission" value-ref="permission"></entry>
      <entry key="kickout" value-ref="kickoutSessionFilter"></entry>
    </util:map>
  </property>
</bean>

Java代碼,下面看實現的Filter代碼。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package com.sojson.core.shiro.filter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONObject;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import com.sojson.common.utils.LoggerUtils;
import com.sojson.core.shiro.cache.VCache;
import com.sojson.core.shiro.session.ShiroSessionRepository;
import com.sojson.core.shiro.token.manager.TokenManager;
/**
 *
 * 開發公司:SOJSON在線工具 <p>
 * 版權所有:© www.sojson.com<p>
 * 博客地址:http://www.sojson.com/blog/ <p>
 * <p>
 *
 * 相同帳號登錄控制
 *
 * <p>
 *
 * 區分 責任人 日期    說明<br/>
 * 創建 周柏成 2016年6月2日  <br/>
 *
 * @author zhou-baicheng
 * @email so@sojson.com
 * @version 1.0,2016年6月2日 <br/>
 *
 */
@SuppressWarnings({"unchecked","static-access"})
public class KickoutSessionFilter extends AccessControlFilter {
 //靜態注入
 static String kickoutUrl;
 //在線用戶
 final static String ONLINE_USER = KickoutSessionFilter.class.getCanonicalName()+ "_online_user";
 //踢出狀態,true標示踢出
 final static String KICKOUT_STATUS = KickoutSessionFilter.class.getCanonicalName()+ "_kickout_status";
 static VCache cache;
 //session獲取
 static ShiroSessionRepository shiroSessionRepository;
 @Override
 protected boolean isAccessAllowed(ServletRequest request,
  ServletResponse response, Object mappedValue) throws Exception {
 HttpServletRequest httpRequest = ((HttpServletRequest)request);
 String url = httpRequest.getRequestURI();
 Subject subject = getSubject(request, response);
 //如果是相關目錄 or 如果沒有登錄 就直接return true
 if(url.startsWith("/open/") || (!subject.isAuthenticated() && !subject.isRemembered())){
  return Boolean.TRUE;
 }
 Session session = subject.getSession();
 Serializable sessionId = session.getId();
 /**
  * 判斷是否已經踢出
  * 1.如果是Ajax 訪問,那么給予json返回值提示。
  * 2.如果是普通請求,直接跳轉到登錄頁
  */
 Boolean marker = (Boolean)session.getAttribute(KICKOUT_STATUS);
 if (null != marker && marker ) {
  Map<String, String> resultMap = new HashMap<String, String>();
  //判斷是不是Ajax請求
  if (ShiroFilterUtils.isAjax(request) ) {
  LoggerUtils.debug(getClass(), "當前用戶已經在其他地方登錄,并且是Ajax請求!");
  resultMap.put("user_status", "300");
  resultMap.put("message", "您已經在其他地方登錄,請重新登錄!");
  out(response, resultMap);
  }
  return Boolean.FALSE;
 }
 //從緩存獲取用戶-Session信息 <UserId,SessionId>
 LinkedHashMap<Long, Serializable> infoMap = cache.get(ONLINE_USER, LinkedHashMap.class);
 //如果不存在,創建一個新的
 infoMap = null == infoMap ? new LinkedHashMap<Long, Serializable>() : infoMap;
 //獲取tokenId
 Long userId = TokenManager.getUserId();
 //如果已經包含當前Session,并且是同一個用戶,跳過。
 if(infoMap.containsKey(userId) && infoMap.containsValue(sessionId)){
  //更新存儲到緩存1個小時(這個時間最好和session的有效期一致或者大于session的有效期)
  cache.setex(ONLINE_USER, infoMap, 3600);
  return Boolean.TRUE;
 }
 //如果用戶相同,Session不相同,那么就要處理了
 /**
  * 如果用戶Id相同,Session不相同
  * 1.獲取到原來的session,并且標記為踢出。
  * 2.繼續走
  */
 if(infoMap.containsKey(userId) && !infoMap.containsValue(sessionId)){
  Serializable oldSessionId = infoMap.get(userId);
  Session oldSession = shiroSessionRepository.getSession(oldSessionId);
  if(null != oldSession){
  //標記session已經踢出
  oldSession.setAttribute(KICKOUT_STATUS, Boolean.TRUE);
  shiroSessionRepository.saveSession(oldSession);//更新session
  LoggerUtils.fmtDebug(getClass(), "kickout old session success,oldId[%s]",oldSessionId);
  }else{
  shiroSessionRepository.deleteSession(oldSessionId);
  infoMap.remove(userId);
  //存儲到緩存1個小時(這個時間最好和session的有效期一致或者大于session的有效期)
  cache.setex(ONLINE_USER, infoMap, 3600);
  }
  return Boolean.TRUE;
 }
 if(!infoMap.containsKey(userId) && !infoMap.containsValue(sessionId)){
  infoMap.put(userId, sessionId);
  //存儲到緩存1個小時(這個時間最好和session的有效期一致或者大于session的有效期)
  cache.setex(ONLINE_USER, infoMap, 3600);
 }
 return Boolean.TRUE;
 }
 @Override
 protected boolean onAccessDenied(ServletRequest request,
  ServletResponse response) throws Exception {
 //先退出
 Subject subject = getSubject(request, response);
 subject.logout();
 WebUtils.getSavedRequest(request);
 //再重定向
 WebUtils.issueRedirect(request, response,kickoutUrl);
 return false;
 }
 private void out(ServletResponse hresponse, Map<String, String> resultMap)
  throws IOException {
 try {
  hresponse.setCharacterEncoding("UTF-8");
  PrintWriter out = hresponse.getWriter();
  out.println(JSONObject.fromObject(resultMap).toString());
  out.flush();
  out.close();
 } catch (Exception e) {
  LoggerUtils.error(getClass(), "KickoutSessionFilter.class 輸出JSON異常,可以忽略。");
 }
 }
 public static void setShiroSessionRepository(
  ShiroSessionRepository shiroSessionRepository) {
 KickoutSessionFilter.shiroSessionRepository = shiroSessionRepository;
 }
 public static String getKickoutUrl() {
 return kickoutUrl;
 }
 public static void setKickoutUrl(String kickoutUrl) {
 KickoutSessionFilter.kickoutUrl = kickoutUrl;
 }
}

前端頁面(登錄頁面)代碼。

?
1
2
3
4
5
6
7
try{
 var _href = window.location.href+"";
 if(_href && _href.indexOf('?kickout')!=-1){
 layer.msg('您已經被踢出,請重新登錄!');
 }
}catch(e){
}

Ok了,這樣效果就出來了。(效果圖)

Shiro 控制并發登錄人數限制及登錄踢出的實現代碼

總結

以上所述是小編給大家介紹的Shiro 控制并發登錄人數限制及登錄踢出的實現代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://blog.csdn.net/ainuser/article/details/62048551

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美视频网站 | 青青久视频 | 中文字幕第一页在线 | 欧美日韩一区二区三区在线观看 | 亚洲成人精品在线 | 欧美aaa级 | 色综合88 | 亚洲人成在线播放 | av免费网站在线观看 | 久久综合另类激情人妖 | 国产资源在线视频 | 精品久久精品久久 | 91精品国产手机 | 在线视频三级 | 国产精品无码久久久久 | 国产免费av网站 | 一区二区三区在线免费观看 | 日韩福利在线 | 人人插人 | 久久久av | 国产成人视屏 | 国产精品成人在线观看 | 欧美视频精品 | 国产成人福利 | 精品一区二区三区久久 | 国产精品123 | 欧美日韩中文在线 | 亚洲人一区二区 | 中文字幕在线一区二区三区 | 日韩久久精品一区二区 | 在线观看中文字幕亚洲 | 欧美精品一区二区三区在线四季 | 五月天一区二区 | 久久久久久久久久久高潮 | 国产一区二区在线视频 | av中文在线 | 午夜操操| 国产精品一卡二卡三卡 | 青青久久 | 欧美日本韩国一区二区三区 | 成人精品鲁一区一区二区 |