1.getsession����Դ��
2.åç¹ç»å½SSOåçåå®ç°
3.SRequest[/login] does not contain handler parameter named 'login'. This 法方法may be caused by whit
getsession����Դ��
对于一个帐号在同一时间只能一个人登录,可以通过下面的源码方法实现:
1 .在用户登录时,把用户添加到一个ArrayList中
2 .再次登录时查看ArrayList中有没有该用户,作用如果ArrayList中已经存在该用户,法方法摩拜交易源码则阻止其登录
3 .当用户退出时,源码需要从该ArrayList中删除该用户,作用getsession源码这又分为三种情况
① 使用注销按钮正常退出
② 点击浏览器关闭按钮或者用Alt+F4退出,法方法可以用javascript捕捉该页面关闭事件,源码
执行一段java方法删除ArrayList中的作用用户
③ 非正常退出,比如客户端系统崩溃或突然死机,法方法可以采用隔一段时间session没活动就删除该session所对应的源码用户来解决,这样用户需要等待一段时间之后就可以正常登录。作用
在LoginAction中定义:
// 用来在服务器端存储登录的法方法买卖 源码所有帐号
public static List logonAccounts;
login() 登录方法中:
// 设置session不活动时间为分
request.getSession().setMaxInactiveInterval(*);
if(logonAccounts==null){
logonAccounts = new ArrayList();
}
// 查看ArrayList中有没有该用户
for (int i = 0; i < logonAccounts.size(); i++) {
Account existAccount = (Account)logonAccounts.get(i);
if(account.getAccountId().equals(existAccount.getAccountId())){
return "denied";
}
}
// 在用户登录时,把sessionId添加到一个account对象中
// 在后面 ③ 需要根据此sessionId删除相应用户
account.setSessionId(request.getSession().getId());
// 该用户保存到ArrayList静态类变量中
logonAccounts.add(account);
return "login";
① 使用注销按钮正常退出
logout() 退出方法中:
if(logonAccounts==null){
logonAccounts = new ArrayList();
}
// 删除ArrayList中的源码用户 ⑴
for (int i = 0; i < logonAccounts.size(); i++) {
Account existAccount = (Account)logonAccounts.get(i);
if(account.getAccountId().equals(existAccount.getAccountId())){
logonAccounts.remove(account);
}
}
② 点击浏览器关闭按钮或者用Alt+F4退出:
在后台弹出一个窗口,在弹出窗口中删除ArrayList中的作用用户
function window.onbeforeunload(){
// 是否通过关闭按钮或者用Alt+F4退出
// 如果为刷新触发onbeforeunload事件,下面if语句不执行
if (event.clientX>document.body.clientWidth && event.clientY<0||event.altKey){
window.open('accountUnbound.jsp',usbhcd源码'',
'height=0,width=0,top=,left=')
}
}
accountUnbound.jsp : 弹出窗口中删除ArrayList中的用户
<%
Account account = (Account) request.getSession().getAttribute("account");
if(account != null){
if(LoginAction.logonAccounts==null){
LoginAction.logonAccounts = new ArrayList();
}
// 删除ArrayList中的用户——下面代码和上面的 ⑴ 处一样
for (int i = 0; i < logonAccounts.size(); i++) {
Account existAccount = (Account)logonAccounts.get(i);
if(account.getAccountId().equals(existAccount.getAccountId())){
logonAccounts.remove(account);
}
}
}
%>
为了保证上面代码可以执行完毕,3秒后关闭此弹出窗口(也位于accountUnbound.jsp中)
<script>
setTimeout("closeWindow();",);
function closeWindow(){
window.close();
}
</script>
③ 使LoginAction 实现implements HttpSessionListener,并实现sessionCreated,sessionDestroyed方法,txt源码在sessionDestroyed中删除ArrayList中的用户(用户超过分钟不活动则执行此方法)
public void sessionDestroyed(HttpSessionEvent event) {
// 取得不活动时的sessionId,并根据其删除相应logonAccounts中的用户
String sessionId = event.getSession().getId();
for (int i = 0; i < logonAccounts.size(); i++) {
Account existAccount = (Account)logonAccounts.get(i);
if(account.getSessionId().equals(existAccount.getSessionId())){
logonAccounts.remove(account);
}
}
}
注:
对于上面的,由于弹出窗口很容易被防火墙或者安全软件阻拦,造成无法弹出窗口,从而短时间不能登录,这种情况可以用AJAX来代替弹出窗口,同样在后台执行删除用户的那段代码,却不会受到防火墙限制:
<script>
// <![CDATA[
var /hsfxuebao?ï¼å¸æ对大家ææ帮å©ï¼è¦æ¯è§å¾å¯ä»¥çè¯éº»ç¦ç»ç¹ä¸ä¸Starå
1. åç³»ç»ç»å½æºå¶1.1 / å?/index.html ?å¦ åæºï¼åè®®ãååã端å£å·ç¸åï¼/ å?/index.html?è·¨å åè®®ä¸åï¼/ å?ç¾åº¦ä¸ä¸ï¼ä½ å°±ç¥é?è·¨å 主ååä¸åï¼test/baiduï¼
/? å /?è·¨å åååä¸åï¼www/blogï¼
:/?å :/?è·¨å 端å£å·ä¸åï¼/ï¼
2.3 å¤ç³»ç»è§£å³æ¹æ¡è½ç¶åç³»ç»çç»å½è§£å³æ¹æ¡å¾å®ç¾ï¼ä½å¯¹äºå¤ç³»ç»åºç¨ç¾¤å·²ç»ä¸åéç¨äºï¼ä¸ºä»ä¹å¢ï¼
åç³»ç»ç»å½è§£å³æ¹æ¡çæ ¸å¿æ¯cookieï¼cookieæºå¸¦ä¼è¯idå¨æµè§å¨ä¸æå¡å¨ä¹é´ç»´æ¤ä¼è¯ç¶æãä½cookieæ¯æéå¶çï¼è¿ä¸ªéå¶å°±æ¯cookieçåï¼é常对åºç½ç«çååï¼ï¼æµè§å¨åéâï¼ç¶åå°å®ä»¬çcookieå设置为âbaidu.comâï¼è¿ç§åæ³ç论ä¸æ¯å¯ä»¥çï¼çè³æ©æå¾å¤å¤ç³»ç»ç»å½å°±éç¨è¿ç§åååå ±äº«cookieçæ¹å¼ãç¶èï¼å¯è¡å¹¶ä¸ä»£è¡¨å¥½ï¼å ±äº«cookieçæ¹å¼åå¨ä¼å¤å±é:
é¦å ï¼åºç¨ç¾¤ååå¾ç»ä¸ï¼
å ¶æ¬¡ï¼åºç¨ç¾¤åç³»ç»ä½¿ç¨çææ¯ï¼è³å°æ¯webæå¡å¨ï¼è¦ç¸åï¼ä¸ç¶cookieçkeyå¼ï¼tomcat为JSESSIONIDï¼ä¸åï¼æ æ³ç»´æä¼è¯ï¼å ±äº«cookieçæ¹å¼æ¯æ æ³å®ç°è·¨è¯è¨ææ¯å¹³å°ç»å½çï¼æ¯å¦javaãphpã.netç³»ç»ä¹é´ï¼
第ä¸ï¼cookieæ¬èº«ä¸å®å ¨ã
å æ¤ï¼æ们éè¦ä¸ç§å ¨æ°çç»å½æ¹å¼æ¥å®ç°å¤ç³»ç»åºç¨ç¾¤çç»å½ï¼è¿å°±æ¯åç¹ç»å½
3. åç¹ç»å½ä»ä¹æ¯åç¹ç»å½ï¼åç¹ç»å½å ¨ç§°Single Sign Onï¼ä»¥ä¸ç®ç§°SSOï¼ï¼æ¯æå¨å¤ç³»ç»åºç¨ç¾¤ä¸ç»å½ä¸ä¸ªç³»ç»ï¼ä¾¿å¯å¨å ¶ä»ææç³»ç»ä¸å¾å°ææèæ éå次ç»å½ï¼å æ¬åç¹ç»å½ä¸åç¹æ³¨é两é¨å
3.1 ç»å½ç¸æ¯äºåç³»ç»ç»å½ï¼ssoéè¦ä¸ä¸ªç¬ç«ç认è¯ä¸å¿ï¼åªæ认è¯ä¸å¿è½æ¥åç¨æ·çç¨æ·åå¯ç çå®å ¨ä¿¡æ¯ï¼å ¶ä»ç³»ç»ä¸æä¾ç»å½å ¥å£ï¼åªæ¥å认è¯ä¸å¿çé´æ¥ææãé´æ¥ææéè¿ä»¤çå®ç°ï¼sso认è¯ä¸å¿éªè¯ç¨æ·çç¨æ·åå¯ç 没é®é¢ï¼å建ææ令çï¼å¨æ¥ä¸æ¥ç跳转è¿ç¨ä¸ï¼ææ令çä½ä¸ºåæ°åéç»å个åç³»ç»ï¼åç³»ç»æ¿å°ä»¤çï¼å³å¾å°äºææï¼å¯ä»¥åæ¤å建å±é¨ä¼è¯ï¼å±é¨ä¼è¯ç»å½æ¹å¼ä¸åç³»ç»çç»å½æ¹å¼ç¸åãè¿ä¸ªè¿ç¨ï¼ä¹å°±æ¯åç¹ç»å½çåçï¼ç¨ä¸å¾è¯´æ
ä¸é¢å¯¹ä¸å¾ç®è¦æè¿°:
ç¨æ·è®¿é®ç³»ç»1çåä¿æ¤èµæºï¼ç³»ç»1åç°ç¨æ·æªç»å½ï¼è·³è½¬è³sso认è¯ä¸å¿ï¼å¹¶å°èªå·±çå°åä½ä¸ºåæ°
sso认è¯ä¸å¿åç°ç¨æ·æªç»å½ï¼å°ç¨æ·å¼å¯¼è³ç»å½é¡µé¢
ç¨æ·è¾å ¥ç¨æ·åå¯ç æ交ç»å½ç³è¯·
sso认è¯ä¸å¿æ ¡éªç¨æ·ä¿¡æ¯ï¼å建ç¨æ·ä¸sso认è¯ä¸å¿ä¹é´çä¼è¯ï¼ç§°ä¸ºå ¨å±ä¼è¯ï¼åæ¶å建ææ令ç
sso认è¯ä¸å¿å¸¦ç令ç跳转ä¼æåç请æ±å°åï¼ç³»ç»1ï¼
ç³»ç»1æ¿å°ä»¤çï¼å»sso认è¯ä¸å¿æ ¡éªä»¤çæ¯å¦ææ
sso认è¯ä¸å¿æ ¡éªä»¤çï¼è¿åææï¼æ³¨åç³»ç»1
ç³»ç»1使ç¨è¯¥ä»¤çå建ä¸ç¨æ·çä¼è¯ï¼ç§°ä¸ºå±é¨ä¼è¯ï¼è¿ååä¿æ¤èµæº
ç¨æ·è®¿é®ç³»ç»2çåä¿æ¤èµæº
ç³»ç»2åç°ç¨æ·æªç»å½ï¼è·³è½¬è³sso认è¯ä¸å¿ï¼å¹¶å°èªå·±çå°åä½ä¸ºåæ°
sso认è¯ä¸å¿åç°ç¨æ·å·²ç»å½ï¼è·³è½¬åç³»ç»2çå°åï¼å¹¶éä¸ä»¤ç
ç³»ç»2æ¿å°ä»¤çï¼å»sso认è¯ä¸å¿æ ¡éªä»¤çæ¯å¦ææ
sso认è¯ä¸å¿æ ¡éªä»¤çï¼è¿åææï¼æ³¨åç³»ç»2
ç³»ç»2使ç¨è¯¥ä»¤çå建ä¸ç¨æ·çå±é¨ä¼è¯ï¼è¿ååä¿æ¤èµæº
ç¨æ·ç»å½æåä¹åï¼ä¼ä¸sso认è¯ä¸å¿åå个åç³»ç»å»ºç«ä¼è¯ï¼ç¨æ·ä¸sso认è¯ä¸å¿å»ºç«çä¼è¯ç§°ä¸ºå ¨å±ä¼è¯ï¼ç¨æ·ä¸å个åç³»ç»å»ºç«çä¼è¯ç§°ä¸ºå±é¨ä¼è¯ï¼å±é¨ä¼è¯å»ºç«ä¹åï¼ç¨æ·è®¿é®åç³»ç»åä¿æ¤èµæºå°ä¸åéè¿sso认è¯ä¸å¿ï¼å ¨å±ä¼è¯ä¸å±é¨ä¼è¯æå¦ä¸çº¦æå ³ç³»:
å±é¨ä¼è¯åå¨ï¼å ¨å±ä¼è¯ä¸å®åå¨
å ¨å±ä¼è¯åå¨ï¼å±é¨ä¼è¯ä¸ä¸å®åå¨
å ¨å±ä¼è¯éæ¯ï¼å±é¨ä¼è¯å¿ é¡»éæ¯
ä½ å¯ä»¥éè¿å客åãç¾åº¦ãcsdnãæ·å®çç½ç«çç»å½è¿ç¨å 深对åç¹ç»å½çç解ï¼æ³¨æè§å¯ç»å½è¿ç¨ä¸ç跳转urlä¸åæ°
3.2 注éåç¹ç»å½èªç¶ä¹è¦åç¹æ³¨éï¼å¨ä¸ä¸ªåç³»ç»ä¸æ³¨éï¼ææåç³»ç»çä¼è¯é½å°è¢«éæ¯ï¼ç¨ä¸é¢çå¾æ¥è¯´æ
sso认è¯ä¸å¿ä¸ç´çå¬å ¨å±ä¼è¯çç¶æï¼ä¸æ¦å ¨å±ä¼è¯éæ¯ï¼çå¬å¨å°éç¥ææ注åç³»ç»æ§è¡æ³¨éæä½
ä¸é¢å¯¹ä¸å¾ç®è¦è¯´æ:
ç¨æ·åç³»ç»1å起注é请æ±
ç³»ç»1æ ¹æ®ç¨æ·ä¸ç³»ç»1建ç«çä¼è¯idæ¿å°ä»¤çï¼åsso认è¯ä¸å¿å起注é请æ±
sso认è¯ä¸å¿æ ¡éªä»¤çææï¼éæ¯å ¨å±ä¼è¯ï¼åæ¶ååºææç¨æ¤ä»¤ç注åçç³»ç»å°å
sso认è¯ä¸å¿åææ注åç³»ç»å起注é请æ±
å注åç³»ç»æ¥æ¶sso认è¯ä¸å¿ç注é请æ±ï¼éæ¯å±é¨ä¼è¯
sso认è¯ä¸å¿å¼å¯¼ç¨æ·è³ç»å½é¡µé¢
4. å®ç°åªæ¯ç®è¦ä»ç»ä¸åºäºjavaçå®ç°è¿ç¨ï¼ä¸æä¾å®æ´æºç ï¼æç½äºåçï¼æç¸ä¿¡ä½ 们å¯ä»¥èªå·±å®ç°ãssoéç¨å®¢æ·ç«¯/æå¡ç«¯æ¶æï¼æ们å çsso-clientä¸sso-serverè¦å®ç°çåè½ï¼ä¸é¢ï¼sso认è¯ä¸å¿=sso-serverï¼
sso-client:
æ¦æªåç³»ç»æªç»å½ç¨æ·è¯·æ±ï¼è·³è½¬è³sso认è¯ä¸å¿
æ¥æ¶å¹¶åå¨sso认è¯ä¸å¿åéç令ç
ä¸sso-serveréä¿¡ï¼æ ¡éªä»¤ççæææ§
建ç«å±é¨ä¼è¯
æ¦æªç¨æ·æ³¨é请æ±ï¼åsso认è¯ä¸å¿åé注é请æ±
æ¥æ¶sso认è¯ä¸å¿ååºç注é请æ±ï¼éæ¯å±é¨ä¼è¯
sso-server:
éªè¯ç¨æ·çç»å½ä¿¡æ¯
åå»ºå ¨å±ä¼è¯
å建ææ令ç
ä¸sso-clientéä¿¡åé令ç
æ ¡éªsso-client令çæææ§
ç³»ç»æ³¨å
æ¥æ¶sso-client注é请æ±ï¼æ³¨éææä¼è¯
æ¥ä¸æ¥ï¼æ们æç §åçæ¥ä¸æ¥æ¥å®ç°ssoå§ï¼
4.1 sso-clientæ¦æªæªç»å½è¯·æ±javaæ¦æªè¯·æ±çæ¹å¼æservletãfilterãlistenerä¸ç§æ¹å¼ï¼æ们éç¨filterãå¨sso-clientä¸æ°å»ºLoginFilter.java类并å®ç°Filteræ¥å£ï¼å¨doFilter()æ¹æ³ä¸å å ¥å¯¹æªç»å½ç¨æ·çæ¦æª
public?void?doFilter(ServletRequest?request,?ServletResponse?response,?FilterChain?chain)?throws?IOException,?ServletException?{ HttpServletRequest?req?=?(HttpServletRequest)?request;HttpServletResponse?res?=?(HttpServletResponse)?response;HttpSession?session?=?req.getSession();if?(session.getAttribute("isLogin"))?{ chain.doFilter(request,?response);return;}//跳转è³sso认è¯ä¸å¿res.sendRedirect("sso-server-url-with-system-url");}4.2 sso-serveræ¦æªæªç»å½è¯·æ±æ¦æªä»sso-client跳转è³sso认è¯ä¸å¿çæªç»å½è¯·æ±ï¼è·³è½¬è³ç»å½é¡µé¢ï¼è¿ä¸ªè¿ç¨ä¸sso-clientå®å ¨ä¸æ ·
4.3 sso-serveréªè¯ç¨æ·ç»å½ä¿¡æ¯ç¨æ·å¨ç»å½é¡µé¢è¾å ¥ç¨æ·åå¯ç ï¼è¯·æ±ç»å½ï¼sso认è¯ä¸å¿æ ¡éªç¨æ·ä¿¡æ¯ï¼æ ¡éªæåï¼å°ä¼è¯ç¶ææ 记为âå·²ç»å½â
@RequestMapping("/login")public?String?login(String?username,?String?password,?HttpServletRequest?req)?{ this.checkLoginInfo(username,?password);req.getSession().setAttribute("isLogin",?true);return?"success";}4.4ãsso-serverå建ææ令çææ令çæ¯ä¸ä¸²éæºå符ï¼ä»¥ä»ä¹æ ·çæ¹å¼çæé½æ²¡æå ³ç³»ï¼åªè¦ä¸éå¤ãä¸æ伪é å³å¯ï¼ä¸é¢æ¯ä¸ä¸ªä¾å
String?token?=?UUID.randomUUID().toString();4.5ãsso-clientåå¾ä»¤çå¹¶æ ¡éªsso认è¯ä¸å¿ç»å½åï¼è·³è½¬ååç³»ç»å¹¶éä¸ä»¤çï¼åç³»ç»ï¼sso-clientï¼åå¾ä»¤çï¼ç¶åå»sso认è¯ä¸å¿æ ¡éªï¼å¨LoginFilter.javaçdoFilter()ä¸æ·»å å è¡
//?请æ±é带tokenåæ°String?token?=?req.getParameter("token");if?(token?!=?null)?{ //?å»sso认è¯ä¸å¿æ ¡éªtokenboolean?verifyResult?=?this.verify("sso-server-verify-url",?token);if?(!verifyResult)?{ res.sendRedirect("sso-server-url");return;}chain.doFilter(request,?response);}verify()æ¹æ³ä½¿ç¨/xuxueli/xxlâ¦Downloadgitee.com/xuxueliâ¦Download5.4 ææ¡£å°å
ä¸æææ¡£
5.5 项ç®ç»æ说æHttpSession?session?=?request.getSession();session.getAttribute("isLogin");.6 åºäºTokenæ¹å¼é¨ç½²ç±äºåå端å离å¼åç模å¼è¾å¤ï¼è¿éåªä»ç»åºäºTokenæ¹å¼é¨ç½²ï¼å¨ä¸äºæ æ³ä½¿ç¨Cookieçåºæ¯ä¸ï¼å¯ä½¿ç¨è¯¥æ¹å¼ï¼å¦éè¦Cookieæ¥çåºäºcookieæ¹å¼é¨ç½²
5.6.1 认è¯ä¸å¿ï¼SSO Serverï¼æ建项ç®åï¼xxl-sso-server
é ç½®æ件ä½ç½®ï¼application.properties
HttpSession?session?=?request.getSession();session.getAttribute("isLogin");.6.2 åç¹ç»éClient端æ建项ç®åï¼xxl-sso-token-sample-springboot
mavenä¾èµ
HttpSession?session?=?request.getSession();session.getAttribute("isLogin");3é ç½®æ件ï¼application.properties
HttpSession?session?=?request.getSession();session.getAttribute("isLogin");4é ç½® XxlSsoTokenFilter
HttpSession?session?=?request.getSession();session.getAttribute("isLogin");.6.3 éªè¯ (模æè¯·æ± Token æ¹å¼æ¥å ¥SSOçæ¥å£)ä¿®æ¹Hostæ件ï¼ååæ¹å¼è®¿é®è®¤è¯ä¸å¿ï¼æ¨¡æè·¨åä¸çº¿ä¸çå®ç¯å¢
HttpSession?session?=?request.getSession();session.getAttribute("isLogin");6åå«è¿è¡ "xxl-sso-server" ä¸ "xxl-sso-token-sample-springboot"
认è¯ä¸å¿æ建æååï¼é»è®¤ä¸ºTokenæ¹å¼ç»éæä¾APIæ¥å£:
1ãç»éæ¥å£ï¼/app/login
codeï¼ è¡¨ç¤ºæåãå ¶ä»å¤±è´¥
msgï¼é误æ示
data: ç»éç¨æ·ç sso sessionid
usernameï¼è´¦å·
passwordï¼è´¦å·
åæ°ï¼POSTåæ°
ååºï¼JSONæ ¼å¼
2ã注éæ¥å£ï¼/app/logout
codeï¼ è¡¨ç¤ºæåãå ¶ä»å¤±è´¥
msgï¼é误æ示
sessionIdï¼ç»éç¨æ·ç sso sessionid
åæ°ï¼POSTåæ°
ååºï¼JSONæ ¼å¼
3ãç»éç¶ææ ¡éªæ¥å£ï¼/app/l
SRequest[/login] does not contain handler parameter named 'login'. This may be caused by whit
é ç½®æ件éä½ æ¢ç¶åäº
parameter="login" scope="request" validate="false"
é£ä¹å¨é¡µé¢formåºè¯¥åæaction=âlogin.do?login=æ¹æ³åâ
é®å·åé¢çlogin对åºçå°±æ¯parameterå¡«åçï¼çå·åé¢åçå°±æ¯ä½ è¦è°ç¨æ¹æ³å.