SpringMVC(7)基于对称加密的7天免密登录

基本思路

  • 登陆时,勾选七天免密登录,将当前对象的Json字符串加密后,保存到客户端的cookie
  • 使用过滤器,当路径是登录页面时,判断当前是否有session,如果有,直接登录进index页面
  • 如果没有session,判断当前是否有名字为User的cookie,
    如果有,进一步判断User在数据库中是否存在
    如果存在,创建一个session,进入index页面
  • 如果不存在cookie,进入登录页面(loginShow)

代码案例

前端页面【bootstrap的写法】【可以换为普通写法】

<form class="form-horizontal" action="login.do" method="post">
			    <!--把标签和控件放在一个带有 class .form-group 的 <div> 中。-->
			    <!--.form-group:使表单元素上下保持间距-->
			    <div class="form-group">
			        <!--向标签添加 class .control-label。使文字紧贴在输入框的左边-->
			        <label for="name" class="col-sm-4 control-label">账号</label>
			        <div class="col-sm-6">
			            <!--form-control:输入框的样式-->
			            <input type="text" class="form-control" id="username" name="username" placeholder="输入账号" value="${username}">
			        </div>
			    </div>
			    <div class="form-group">
			        <!--向标签添加 class .control-label。使文字紧贴在输入框的左边-->
			        <label for="name" class="col-sm-4 control-label">密码</label>
			        <div class="col-sm-6">
			            <!--form-control:输入框的样式-->
			            <input type="password" class="form-control" id="password" name="password" placeholder="输入密码">
			        </div>
			    </div>
			    <div class="form-group">
			    	<!--offset  列 sm 偏移量 4 -->
			    	<div class="checkbox col-sm-offset-4">
					  <label>
					    <input type="checkbox" id="savePwd" name="savePwd"> 7天免密登录
					  </label>
					</div>
			    </div>
			    <div class="form-group">
 			    	<!--offset  列 sm 偏移量 4 -->
			        <div class="col-sm-offset-4">
			        	<input type="submit" class="btn btn-primary" value="登录">
			        	<input type="reset" class="btn btn-primary" value="重置">
<!-- 			            <button type="submit" class="btn btn-primary">添加</button> -->
			        </div>
			    </div>
			</form>

在这里插入图片描述

登录后,创建session,创建cookie存储用户加密后的信息

@RequestMapping("login")//表示user/login.do(有后缀)
	public String login(HttpServletRequest request,HttpServletResponse response,User u,boolean savePwd) {
		u.setPassword(MD5Utils.getMD5Value(u.getPassword()));//密码加密
		
		UserService userService=new UserServiceImpl();
		User user=userService.searchByUser(u);//如果找不到,返回null
		if(user!=null) {//登陆成功
			//a.登陆成功,在Session存一个user对象--》IndexController
			//【session:权限控制,用于判断是否登陆成功,通过过滤器实现】
			HttpSession session = request.getSession();//返回request的session,如果没有session就创建一个session
			session.setAttribute("user", user);
			
			//session设置失效时间是从什么时候算起?
			//从session不活动的时候开始计算,如果session一直活动,session就总不会过期。 
			//从该Session未被访问,开始计时; 一旦Session被访问,计时清0;
			//Session的默认失效时间是30分钟,关闭当前标签(不关闭浏览器),可以再次直接进入任何路径
			session.setMaxInactiveInterval(9000);//session存活时间,单位:秒,15分钟
			//注意:此时,cookie中保存JSESSIONID的时间是默认的-1,
			//      即,关闭浏览器,cookie的JSESSIONID失效
			//      所以,再次打开浏览器时,虽然服务器的session仍然有效,但是,cookie的JSESSIONID失效
			//		=》session是基于cookie的,所以,需要重新登录
			
			//session 并不是随着浏览器的关闭而关闭的
			//session只会随着其生命周期结束或者强制销毁
			
			//确保JSESSIONID不随着浏览器的关闭而失效的方法【保证浏览器再次打开,也可以使用当前的cookie】
			//CookieUtils.createCookie(response,"JSESSIONID",session.getId(),1);//关闭浏览器,在打开浏览器,也能登陆成功
			//但是,浏览器关闭之后,session就应该失效,所以,通常不使用上面的写法【此处,作为尝试】
			
			if(savePwd) {//七天免密登录
				//创建cookie记录,name为User,value为当前user的json加密信息,存活时间7天
				String userJson=AESUtils.key2Json(user);//将user转变为userJson
				
				//createKey()会自动创建一个key
				//Key key=AESUtils.createKey();
				Key key=AESUtils.readKey();//获取文件中的key
				String encodeUser=AESUtils.encode(userJson,key);//对称加密,userJson加密为encodeUser
				
				CookieUtils.createCookie(response, "User",encodeUser, 7);//保存到cookie
			}
			
			
			//1.创建cookie,并发送到客户端
			//  每次登录,都创建当前username对象,并覆盖原来的cookie
			//  Cookie是可以覆盖的,如果重复写入同名的Cookie,那么将会覆盖之前的Cookie。
			CookieUtils.createCookie(response,"username",user.getUsername());
			
			return "redirect:/index.do";/* /index.do 表示:项目工程名//index.do */
		}else {
			request.setAttribute("msgr", "用户名或密码错误!");
			//model.addAttribute("msgr", "用户名或密码错误!");
			return "login";//不规范的写法,为了获取cookie中的用户名
		}
	}
  • 如果savePwd时true,表示勾选了,七天免密登录
  • AESUtils.key2Json(user):将User对象变为Json字符串
  • AESUtils.readKey():获取服务器中的key文件
  • AESUtils.encode(userJson,key):对称加密
  • CookieUtils.createCookie(response, “User”,encodeUser, 7):创建cookie,保存7天

使用过滤器,对登录页面进行过滤,判断session和cookie

@WebFilter(value= {"/user/showLogin.do"})
public class PwdFreeLoginFilter implements Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request1 =(HttpServletRequest) request;
		HttpServletResponse response1 =(HttpServletResponse) response;
		HttpSession session =request1.getSession();
		//System.out.println("PwdFreeLoginFilter:"+session.getAttribute("user"));
		UserService userService=new UserServiceImpl();
		
		if(session.getAttribute("user")!=null) {//如果session有效,直接进入首页
			response1.sendRedirect(request1.getContextPath()+"/index.do");//使用绝对路径:项目名+/user/showLogin.do
		}else{//如果session失效
			ObjectMapper mapper=new ObjectMapper();
			String encodeUser=CookieUtils.getCookie(request1, "User");
			
			if(encodeUser!=null) {//判断cookie是否存在user的id=》User
				Key key=AESUtils.readKey();//获取文件中的key
				String userJson=AESUtils.decode(encodeUser,key);//对称解密,将encodeUser还原回userJson
				User u=AESUtils.json2Key(userJson,User.class);//将userJson还原为user
				User user=userService.searchByUser(u);//如果找不到,返回null
				if(user!=null) {//登陆成功
					//创建session
					session.setAttribute("user", user);
					session.setMaxInactiveInterval(9000);//session存活时间,单位:秒,15分钟
					request.getRequestDispatcher("/WEB-INF/index.jsp").forward(request1, response1);//不正规的写法
				}
				chain.doFilter(request1, response1);//进入登录页面【进入当前页面】
			}else {//cookie不存在用户信息
				chain.doFilter(request1, response1);//进入登录页面【进入当前页面】
			}
		}
	}
}

难点备注

  • 原本是想将key也存储到cookie中的,但是key转换为JSON之后,反序列化失败

  • 查找原因是:Jackson的ObjectMapper类的readValue会调用无参构造方法(不一定准确,网上的说法)

  • 我自己在使用的时候,发现Jackson的ObjectMapper类的writeValueAsString会调用setter方法
    因为我在密码的set方法内进行了加密,但是writeValueAsString转化对象为Json后,原来已经加密的密码又加密了一次

  • 所以,最后使用了ObjectInputStream流进行了反序列化,key密钥文件保存在服务器

注:对称加密工具类在另一篇文章中,需要的请去自取

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值