SpringMVC攔截器實(shí)現(xiàn)單點(diǎn)登錄
單點(diǎn)登錄的功能在實(shí)際的應(yīng)用場(chǎng)景中還是很重要的,邏輯上我們也不允許一個(gè)用戶(hù)同時(shí)在進(jìn)行著兩個(gè)操作,下面就來(lái)了解一下SpringMVC的單點(diǎn)登錄實(shí)現(xiàn)
SpringMVC的攔截器不同于Spring的攔截器,SpringMVC具有統(tǒng)一的入口DispatcherServlet,所有的請(qǐng)求都通過(guò)DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也沒(méi)有代理,同時(shí)SpringMVC管理的Controller也不有代理。
1,先探究一個(gè)基本的實(shí)現(xiàn)原理:這個(gè)功能還是比較簡(jiǎn)單的,就是對(duì)于同一個(gè)web項(xiàng)目同一個(gè)時(shí)間只能有一個(gè)用戶(hù)在進(jìn)行操作,所以這里就涉及到一個(gè)異地登錄的發(fā)現(xiàn),而這里就推出兩條路,1是服務(wù)器發(fā)現(xiàn)已登錄的用戶(hù)通過(guò)另一個(gè)IP再次執(zhí)行了登錄操作,然后主動(dòng)推送一個(gè)提醒告訴第一個(gè)用戶(hù)賬號(hào)異地登錄;2是當(dāng)用戶(hù)進(jìn)行操作的時(shí)候發(fā)現(xiàn)自己的賬號(hào)被擠掉了,有異地登錄。關(guān)于這兩個(gè)方案,第一種是比較具有實(shí)時(shí)性的但是還在探究中,下面重點(diǎn)說(shuō)一說(shuō)第二種方式。
2,實(shí)現(xiàn)第二種也比較簡(jiǎn)單,兩個(gè)操作,一是在用戶(hù)表中多加一個(gè)字段,用來(lái)存儲(chǔ)登錄用戶(hù)的SessionId,因?yàn)槊恳粋€(gè)request請(qǐng)求都會(huì)對(duì)應(yīng)一個(gè)唯一不重復(fù)的Sessionid,然后呢就是用攔截器技術(shù)了,對(duì)用戶(hù)的操作進(jìn)行攔截,在攔截器中首先是對(duì)登錄頁(yè)面的相關(guān)url請(qǐng)求進(jìn)行放行,然后還有的就是登錄校驗(yàn)的請(qǐng)求放行。最后再對(duì)用戶(hù)進(jìn)行過(guò)濾,(關(guān)于用戶(hù)登錄,在驗(yàn)證成功時(shí),不僅要把用戶(hù)存入Session中用于登錄攔截的驗(yàn)證,還需要把Session的ID存入用戶(hù)表中對(duì)應(yīng)的Sessionid)對(duì)于此次請(qǐng)求的request可以獲取到Session及其ID然后再根據(jù)這個(gè)ID與數(shù)據(jù)庫(kù)中的Sessionid進(jìn)行比較是否相同相同則通過(guò)放行,不同則提示下線(xiàn)跳轉(zhuǎn)登錄,因?yàn)樵谝淮斡脩?hù)連接服務(wù)器操作中會(huì)存在一個(gè)Session只要Session不過(guò)期每次用戶(hù)發(fā)起的操作的request的Session的id都是一致的所以會(huì)和登錄時(shí)存入數(shù)據(jù)庫(kù)中的id匹配,當(dāng)有其他人通過(guò)其他設(shè)備再用同一個(gè)賬號(hào)進(jìn)行登錄時(shí)會(huì)重新建立Session會(huì)刷新數(shù)據(jù)庫(kù)中的Sessionid而自己的Sessionid還是不變的,但是數(shù)據(jù)庫(kù)中的Session已經(jīng)發(fā)生了改變,所以在攔截器中校驗(yàn)數(shù)據(jù)庫(kù)中Sessionid是否一致時(shí)就會(huì)失敗從而攔截用戶(hù)操作達(dá)到單用戶(hù)登錄的功能,(關(guān)于Session的說(shuō)明,當(dāng)用戶(hù)初次與服務(wù)器連接時(shí)會(huì)在服務(wù)器端創(chuàng)建一個(gè)Session,而之后用戶(hù)發(fā)起的每一次操作request中都會(huì)攜帶這個(gè)Session的id而出現(xiàn)一些情況Session的失效,用戶(hù)長(zhǎng)時(shí)間沒(méi)有與服務(wù)器之間進(jìn)行操作,用戶(hù)退出登錄主動(dòng)讓Session失效,用戶(hù)關(guān)閉瀏覽器,或者服務(wù)器重新啟動(dòng))
下面是SpringMVC中攔截器的實(shí)現(xiàn)
public class SingleUserInterceptor implements HandlerInterceptor {
@Autowired
private userMapper mapper;
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
// TODO Auto-generated method stub
}
public Boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
String url = arg0.getRequestURI();
//如果攔截到的是登錄的頁(yè)面的話(huà)放行
if(url.indexOf("login.jsp")>=0||url.indexOf("new/login")>=0||url.indexOf("checkuser")>=0){
return true;
}
//如果用戶(hù)名存在放心(即登錄放行)
Integer user = (Integer) arg0.getSession().getAttribute("user");
if(user!=null){
String sessionid = mapper.getUserEntity(Integer.valueOf(user)).getSessionid();
if(sessionid.equals(arg0.getSession().getId())){
return true;
} else{
arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);
arg1.setContentType("text/html; charset=utf-8");
PrintWriter out = arg1.getWriter();
out.println("<html>");
out.println("<script>");
out.println("alert('您的賬號(hào)在別地登錄,您被迫下線(xiàn)')");
out.println("window.open ('" + arg0.getContextPath()
+ "/new/login','_top');");
out.println("</script>");
out.println("</html>");
// arg0.getRequestDispatcher("login.jsp").forward(arg0, arg1);
return false;
}
}
arg0.getRequestDispatcher("login.jsp").forward(arg0, arg1);
return false;
}
}
以上的代碼即可實(shí)現(xiàn)當(dāng)同一個(gè)用戶(hù)多次登錄時(shí),第一個(gè)登錄用戶(hù)在進(jìn)行操作時(shí)會(huì)被擠下線(xiàn)的功能,可以實(shí)現(xiàn)先提示賬號(hào)異地登錄,然后跳轉(zhuǎn)登錄頁(yè)面的功能。此處需要說(shuō)明這個(gè)簡(jiǎn)單的alert提示功能的要點(diǎn)如果這要想出現(xiàn)這個(gè)alert必須能夠時(shí)能夠讓請(qǐng)求結(jié)束,然后response的打印功能輸出那個(gè)alert的提示語(yǔ)句,所以注釋掉的那句跳轉(zhuǎn)語(yǔ)句不能有,有則不會(huì)出alert提示語(yǔ)句,因?yàn)槟愕牟僮鳑](méi)有正確的結(jié)束而是被轉(zhuǎn)發(fā)或者重定向?yàn)槠渌僮髁瞬徽撜_與否都是其他的action向頁(yè)面的輸出了,所以你的response打印語(yǔ)句就不會(huì)出現(xiàn)。所以正確的做法是:攔截請(qǐng)求不在放行(returnfalse),此時(shí)請(qǐng)求還是原來(lái)的請(qǐng)求,并不會(huì)跳轉(zhuǎn),而response回頁(yè)面的打印信息則可以顯示,至于跳轉(zhuǎn)登錄頁(yè)面則可以用:out.println("window.open('"+arg0.getContextPath()+"/new/login','_top');");來(lái)實(shí)現(xiàn)即在response所輸出的一段js中執(zhí)行了一個(gè)action請(qǐng)求,指向登錄頁(yè)面。
通過(guò)上面的代碼基本上已經(jīng)算是實(shí)現(xiàn)了單用戶(hù)登錄的功能,但是會(huì)發(fā)現(xiàn)ajax請(qǐng)求的操作并沒(méi)有能夠在異地登錄時(shí)指向登錄頁(yè)面也沒(méi)有提示信息,先說(shuō)明一下原因,因?yàn)槟愕腶jax時(shí)在進(jìn)行一個(gè)異步請(qǐng)求,而且也在處理器映射器中匹配到了請(qǐng)求的url所以它會(huì)視為請(qǐng)求成功(返回狀態(tài)碼為200)而上面的response打印的js語(yǔ)句則會(huì)變?yōu)閟uccess中請(qǐng)求成功的,返回值,大家可以嘗試一下把上面的這句話(huà):arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);注釋掉。這時(shí)需要進(jìn)行一些其他操作,首先就是剛剛提到的語(yǔ)句arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);他的功能是設(shè)置response返回的狀態(tài)碼,上面的設(shè)置表示將返回狀態(tài)碼504代表請(qǐng)求出錯(cuò),此時(shí)ajax請(qǐng)求就不會(huì)再在success方法中響應(yīng),而是會(huì)響應(yīng)ajax的error方法,所以只需要再在ajax的error中執(zhí)行對(duì)應(yīng)的方法即可例如:
$.ajax({
url:'new/msd2',
success:function(a){
alert(a);
},
error:function(rs){
if(rs.status==504){
document.write(rs.responseText);
}
}
});
當(dāng)ajax請(qǐng)求因?yàn)楫惖氐卿洷粩r截時(shí)通過(guò)設(shè)置arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);可以使請(qǐng)求的返回狀態(tài)變?yōu)?04出錯(cuò),然后由error方法響應(yīng),當(dāng)判斷到狀態(tài)是自己所設(shè)置的狀態(tài)碼時(shí)再document.write(rs.responseText);responseText即為攔截器中所向前臺(tái)打印的js語(yǔ)句,而要這些語(yǔ)句能夠執(zhí)行則需要document.write();方法將那些代碼寫(xiě)入dom讓其生效,至此,所有的請(qǐng)求,異步ajax請(qǐng)求的單點(diǎn)登錄基本都已實(shí)現(xiàn)。
留此文只記錄關(guān)鍵代碼及思想及操作的原理
總結(jié)
以上就是本文關(guān)于SpringMVC攔截器實(shí)現(xiàn)單點(diǎn)登錄的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持。
- 詳解springmvc控制登錄用戶(hù)session失效后跳轉(zhuǎn)登錄頁(yè)面
- SpringMVC攔截器實(shí)現(xiàn)登錄認(rèn)證
- Spring MVC+mybatis實(shí)現(xiàn)注冊(cè)登錄功能
- SpringMVC 實(shí)現(xiàn)用戶(hù)登錄實(shí)例代碼
- Java編程實(shí)現(xiàn)springMVC簡(jiǎn)單登錄實(shí)例
- springmvc+spring+mybatis實(shí)現(xiàn)用戶(hù)登錄功能(上)
- springmvc下實(shí)現(xiàn)登錄驗(yàn)證碼功能示例
- Spring mvc 實(shí)現(xiàn)用戶(hù)登錄的方法(攔截器)
- spring mvc實(shí)現(xiàn)登錄賬號(hào)單瀏覽器登錄
- spring?MVC實(shí)現(xiàn)簡(jiǎn)單登錄功能
相關(guān)文章
mybatis-plus 通用字段自動(dòng)化(如邏輯刪除和更新時(shí)間等)
這篇文章主要介紹了mybatis-plus 通用字段自動(dòng)化(如邏輯刪除和更新時(shí)間等),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Java基礎(chǔ)知識(shí)精通數(shù)組的使用
數(shù)組對(duì)于每一門(mén)編程語(yǔ)言來(lái)說(shuō)都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語(yǔ)言對(duì)數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java?語(yǔ)言中提供的數(shù)組是用來(lái)存儲(chǔ)固定大小的同類(lèi)型元素2022-04-04
Json讀寫(xiě)本地文件實(shí)現(xiàn)代碼
今天沒(méi)事研究了下Gson,寫(xiě)了個(gè)工具類(lèi),需要的朋友可以參考下2014-03-03
詳解Spring DeferredResult異步操作使用場(chǎng)景
本文主要介紹了Spring DeferredResult異步操作使用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
Java 數(shù)據(jù)結(jié)構(gòu)鏈表操作實(shí)現(xiàn)代碼
這篇文章主要介紹了Java 數(shù)據(jù)結(jié)構(gòu)鏈表操作的相關(guān)資料,并附實(shí)例代碼,需要的朋友可以參考下2016-10-10
mybatis plus自動(dòng)生成代碼tinyint(1)自動(dòng)轉(zhuǎn)換為Boolean的問(wèn)題及解決
這篇文章主要介紹了mybatis plus自動(dòng)生成代碼tinyint(1)自動(dòng)轉(zhuǎn)換為Boolean的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
springboot接口如何多次獲取request中的body內(nèi)容
這篇文章主要介紹了springboot接口多次獲取request中的body內(nèi)容的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
java項(xiàng)目構(gòu)建Gradle的使用教程
這篇文章主要為大家介紹了java項(xiàng)目構(gòu)建Gradle的使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
java設(shè)計(jì)模式-單例模式實(shí)現(xiàn)方法詳解
單例模式,屬于創(chuàng)建類(lèi)型的一種常用的軟件設(shè)計(jì)模式。通過(guò)單例模式的方法創(chuàng)建的類(lèi)在當(dāng)前進(jìn)程中只有一個(gè)實(shí)例(根據(jù)需要,也有可能一個(gè)線(xiàn)程中屬于單例2021-07-07
SpringCloud之Admin服務(wù)監(jiān)控實(shí)現(xiàn)流程示例詳解
這篇文章主要為大家介紹了SpringCloud之Admin服務(wù)監(jiān)控流程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09

