整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

我的Java Web之路65 - 实现用户登出/退出功能

系列文章旨在记录和总结自己在Java Web开发之路上的知识点、经验、问题和思考,希望能帮助更多(Java)码农和想成为(Java)码农的人。

提示:尽量使用头条APP阅读,头条网页展示代码会有问题。

目录

  1. 介绍
  2. 原有的用户退出功能
  3. 思路
  4. 修改include.jsp
  5. 添加处理用户退出请求的动作
  6. 总结

介绍

前面的文章我们实现了租房网平台的用户注册、用户登录、会话跟踪等功能,本篇文章继续实现用户的登出/退出功能。

原有的用户退出功能

实际上,我们之前的版本中,只要用户登录之后,在每个页面当中已经有退出按钮,如下图:


其对应的代码在我们的 include.jsp 中:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.List" %>
<%@ page import="houserenter.entity.House" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>租房网</title>
</head>
<body>
<h1>你好,${sessionScope.userName}!欢迎来到租房网! <a href="login.html">退出</a></h1>
<br><br>

可以看到,这个退出按钮就是一个普通的链接,直接返回到登录页面而已。那这样有什么不好的地方呢?我们做这样一个实验:

  1. 先登录到租房网平台;
  2. 登录后可以打开其他页面,我这里假设打开某个房源详情页面,其URL是:http://localhost:8080/house-renter/house-details.action?houseId=1
  3. 然后点击退出,会跳转到登录页面;
  4. 此时我直接在浏览器的地址栏中重新输入上述URL,可以新开一个浏览器标签页,甚至另外打开一个浏览器进程(不过必须是同一款浏览器,我这里是谷歌浏览器),敲回车;
  5. 结果是我跳过了登录步骤,直接打开了该房源详情页面。

结论就是这样简单的登录功能很不安全。

究其原因,其实是我们采用了session进行会话跟踪,只要session不过期,Servlet容器(我们这里是Tomcat)中的该session对象就还有效,绑定到该session对象中的数据也就还有效。

不过,因为HTTP是基于TCP的,所以不同的TCP连接肯定会产生不同的session,大家有兴趣的话可以自行测试一下TCP连接和session之间的关系。

思路

所以,我们的用户退出功能必须是这样的:

  1. 用户点击退出按钮;
  2. Servlet容器必须感知到用户的退出;
  3. Servlet容器销毁该用户的session。

修改include.jsp

Servlet容器感知用户的退出很简单,只要发送一个请求给Servlet容器即可。

所以我们设计一个用户退出的动作,让上面的退出按钮指向该动作:

<h1>你好,${sessionScope.userName}!欢迎来到租房网! <a href="logout.action">退出</a></h1>

添加处理用户退出请求的动作

我们可以在HouseRenterController中添加处理用户退出请求的动作:

	@GetMapping("/logout.action")
	public ModelAndView getLogout(HttpSession session) {
		System.out.println("session: " + session);
		System.out.println("session id: " + session.getId());
    
		session.invalidate();
    
		ModelAndView mv = new ModelAndView();
		mv.setViewName("redirect:login.html");
		return mv;
	}

重点关注的是,我们调用了HttpSession的invalidate()方法,这样我们就销毁了该session。

我们是如何得知该方法的呢?我们可以充分利用IDE的自动补足功能,然后查看每一个方法的javadoc:


可以发现invalidate()方法就是用来使此session无效,并解除绑定到它的任何对象。

总结

大家可以自行验证一下,经过这样改造后,上述问题得到解决。

  • 调用HttpSession的invalidate()方法可以使会话无效。

ET+EF+MVC开发接口用户退出登陆接口和页面退出登陆实例,开发应用的时候都会遇到,笔者提供二个方法,以供参考:

一、接口 退出登陆方法



[HttpGet]

public HttpResponseMessage PA_ParentLogout(decimal ParentloginID, string UsrMp, string Token = null)

{

HttpResponseMessage result = null;

var ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.失败 + "\",\"msg\":\"退出失败\",\"data\":\"\"}";

if (ParentloginID>0)

{

#region 验证token

if (!string.IsNullOrEmpty(Token))

{

int m = new WisdomStars.Bll.Api.Common().PUB_VerificationToken(Token);

if (m <= 0)

{

ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.失败 + "\",\"msg\":\"登录失效\",\"data\":\"\"}";

result = new HttpResponseMessage { Content = new StringContent(ReturnStr, Encoding.GetEncoding("UTF-8"), "application/json") };

return result;

}

}

else

{

ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.失败 + "\",\"msg\":\"token不能为空\",\"data\":\"\"}";

result = new HttpResponseMessage { Content = new StringContent(ReturnStr, Encoding.GetEncoding("UTF-8"), "application/json") };

return result;

}

#endregion 验证token

HashOperator operators1 = new HashOperator();

string key = Utils.GetDescription(KeyEnum.LoginUserCache.HXAppVaildParent) + UsrMp;

var ser = new ObjectSerializer();

ef.Configuration.ProxyCreationEnabled = false;

bool IsExist = operators1.Exist<string>(key, key);

if (IsExist == true)

{

//先删除redis中的key

operators1.Remove(key, key);

ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.成功 + "\",\"msg\":\"退出成功\",\"data\":\"\"}";

#region 再清空手机token

ef.HX_Parentlogin.Where(a => a.ParentloginID == ParentloginID && a.GuardianTel == UsrMp).Update(p => new HX_Parentlogin

{

mobiletoken = "",

client = 0

});

#endregion 清空手机token

}

else

{

ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.成功 + "\",\"msg\":\"退出成功\",\"data\":\"\"}";

#region 清空手机token

ef.HX_Parentlogin.Where(a => a.ParentloginID == ParentloginID && a.GuardianTel == UsrMp).Update(p => new HX_Parentlogin

{

mobiletoken = "",

client = 0

});

#endregion 清空手机token

}

}

result = new HttpResponseMessage { Content = new StringContent(ReturnStr, Encoding.GetEncoding("UTF-8"), "application/json") };

return result;

}

二、页面退出登陆方法,需要清除所有redis中的键值对。



#region 退出 + public ActionResult Logout()

public ActionResult Logout()

{

LoginInfo loginModel = Distribution.Common.Utils.GetAdminModel();

#region 获取登录信息

decimal adminUsrID = loginModel.adminUsrID;

var username = loginModel.Mobile.ToString();

#endregion 获取登录信息


if (adminUsrID > 0 && !string.IsNullOrEmpty(username))

{

#region 清除redis

HashOperator operators1 = new HashOperator();

var ser = new ObjectSerializer();

ef.Configuration.ProxyCreationEnabled = false;

HX_AdminUser m = ef.HX_AdminUser.Where(a=>a.adminUsrID== adminUsrID).AsNoTracking().FirstOrDefault();

string key = HX.Common.Utils.GetDescription(KeyEnum.LoginUserCache.HXDistributor) + username;


operators1.Remove(key);

string key2 = HX.Common.Utils.GetDescription(KeyEnum.LoginUserCache.HXDistributorCacheJurisdiction) + "_" + adminUsrID.ToString() + "_" + m.subsidiary_id.ToString();

operators1.Remove(key2);

#endregion 清除redis

HttpCookie aCookie = new HttpCookie("userInfo");

aCookie.Expires = DateTime.Now.AddDays(-1);

Response.AppendCookie(aCookie);

return Redirect("/Home/Login");

}

else

{

return Redirect("/Home/Login");

}

}

#endregion 退出

续之前完成的内容,首先创建一个常量类

常量类的内容

服务器端渲染

前后端分离

完成后台管理登录页面

进入前端静态资源

创建后台管理员登录页面admin-login.jsp

完成内容

然后完成页面跳转

配置mvc:view-controller

完成配置

启动服务访问一下

localhost:8080/learn-admin-webui/admin/to/login/page.html

修饰system-error.jsp

Md5加密工具方法

添加到类

编写代码

接着

测试下