一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

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

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 [email protected]
 * @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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 歪歪私人影院成人毛片 | 国产第一福利影院 | 色香婷婷 | 含羞草传媒一天免费看下 | 成成人看片在线 | 国产成人综合精品 | 操破苍穹在线 | 2020年最新国产精品视频免费 | 久久re热在线视频精99 | a级毛片毛片免费观看永久 a级黄色片免费 | 精品成人网| 国产清纯白嫩大学生正在播放 | 欧美在线观看网址 | 成人影院在线观看免费 | 久久青草免费91线频观看站街 | 日本玖玖视频 | 免费精品一区二区三区在线观看 | 2019亚洲男人天堂 | 肉色欧美久久久久久久蜜桃 | 国产欧美va欧美va香蕉在线观 | 日本精品久久久久久久久免费 | 2021福利视频| 三级网站午夜三级 | 三级视频中文字幕 | 四虎网址大全 | 午夜爱爱爱爱爽爽爽视频网站 | 久久视频这有精品63在线国产 | 美女脱了内裤打开腿让人桶网站o | 国产欧美成人不卡视频 | 超级乱淫伦小说1女多男 | 青柠影视在线播放观看高清 | 亚洲视频第一页 | 韩国久久 | 猫影视tv接口 | 91李宗精品72集在线观看 | 国产香蕉在线视频 | 亚洲国产一区二区三区青草影视 | 国产肥老上视频 | 精品久久久噜噜噜久久7 | 精品国产乱码久久久久久软件 | 青青草原在线免费 |