8、UMS-验证码校验【阶段2】
8.1、需求说明
8.2、点击切换验证码
8.2.1、需求分析
8.2.2、代码实现
/login/login.jsp
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js"></script> <script type="text/javascript"> var m1Src;//图片验证码src $(function(){ //为验证码图片绑定点击切换图片功能 $("#m1").click(function(){ var m1 = $(this); if(m1Src==undefined){ m1Src = m1.prop("src"); } m1.prop("src",m1Src+"&t="+new Date().getTime()); }); }); </script> <tr> <td height="30" nowrap> <strong><font color="000F60">验证码: </font> </strong> </td> <td> <input type="text" name="verifyCode" class="text" style="width: 50px;"/> <img id="m1" src="<%=pageContext.getServletContext().getContextPath()%>/vc?method=vc" style="height:30px;width:100px;"/> </td> </tr>
VerifyCodeServlet
/** * 生成验证码,正确答案保存session */ public void vc() throws IOException { String vci = createVerifyCodeImage(); System.out.println(vci); getRequest().getSession().setAttribute("vci",vci); }
8.3、验证码校验
8.3.1、需求分析
8.3.2、代码实现
/login/login.jsp <tr> <td height="30" nowrap> <strong><font color="000F60">验证码: </font> </strong> </td> <td> <input type="text" name="verifyCode" class="text" style="width: 50px;"/> <img id="m1" src="<%=pageContext.getServletContext().getContextPath()%>/vc?method=vc" style="height:30px;width:100px;"/> </td> </tr>
UserServlet
/** * 用户登录 * @return */ public String login(){ //一、先进行验证码校验 //1、分别获取表单验证码和正确验证码 String verifyCode = getRequest().getParameter("verifyCode"); String vci = (String) getRequest().getSession().getAttribute("vci"); //2、为了防止被重复校验验证码,正确验证码使用一次,就要从session中消除 getRequest().getSession().removeAttribute("vci"); //3、校验判断,若校验失败,直接返回错误信息,不用进行用户登录判断 //若用户未提交验证码 或者 正确验证码不存在 或者 两个验证码不同 ABCD和 abcd 相同 if(verifyCode==null || vci==null || !vci.equalsIgnoreCase(verifyCode)){ //校验失败 getRequest().setAttribute("errorMsg","验证码校验失败"); return "forward:/login/login.jsp"; } //4、校验成功,继续进行登录校验【无代码,直接向后运行】 //二、再进行用户登录校验 //1、接收表单参数 User param = toBean(User.class); //2、调用service进行登录处理 User result = null; try { result = userService.login(param); } catch (Exception e) { //抛出异常,登录也是失败 getRequest().setAttribute("errorMsg",e.getMessage()); return "forward:/login/login.jsp"; } //3、根据返回结果,跳转不同的页面 if(result!=null){ //登录成功 getRequest().getSession().setAttribute("loginUser",result); return "redirect:/index.jsp"; }else{ //登录失败 getRequest().setAttribute("errorMsg","用户名或密码错误"); return "forward:/login/login.jsp"; } }
9、UMS-记住用户名【阶段2】
9.1、需求说明
9.2、需求分析
分析:
关键点:
1、使用cookie技术保存数据到浏览器7天
Cookie c = new Cookie("key","value");
c.setMaxAge(60*60*24*7);//秒
getResponse().addCookie(c);
2、cookie数据JSP回显
<%
//查找指定cookie的固定代码格式
Cookie[] arr = request.getCookies();
String value = "";//开关
//若浏览器没有发来任何cookie,null
if(arr!=null){
for(Cookie c:arr){
if(c.getName().equals("要查找的cookie名")){
value=c.getValue();
break;
}
}
}
//JSP数据回显
//回显
out.write(value);
%>
<%=cookieValue%>
3、cookie覆盖问题
两个cookie是追加还是相互覆盖主要看 唯一标识(域名+有效路径+cookie名)
注意:因为都是一个服务器进行编写,所以域名默认相同,我们在进行编码时,cookie名肯定相同。
有效路径统一设置为项目名: /项目名
4、cookie保存中文问题
cookie不能直接保存中文。
URL编码来保存中文,URL解码来读取中文。
URL编码:URLEncoder.encode("","utf-8");
URL解码:URLDecoder.decode("","utf-8");
流程:
9.3、代码实现
//cookie数据保存:
/login/login.jsp
<tr> <td height="30" nowrap> </td> <td> <input type="checkbox" name="autoLogin" value="yes"/>自动登录 <input type="checkbox" name="remember" value="yes"/>记住用户名 </td> </tr>
UserServlet
/** * 用户登录 * @return */ public String login() throws UnsupportedEncodingException { //一、先进行验证码校验 //1、分别获取表单验证码和正确验证码 String verifyCode = getRequest().getParameter("verifyCode"); String vci = (String) getRequest().getSession().getAttribute("vci"); //2、为了防止被重复校验验证码,正确验证码使用一次,就要从session中消除 getRequest().getSession().removeAttribute("vci"); //3、校验判断,若校验失败,直接返回错误信息,不用进行用户登录判断 //若用户未提交验证码 或者 正确验证码不存在 或者 两个验证码不同 ABCD和 abcd 相同 if(verifyCode==null || vci==null || !vci.equalsIgnoreCase(verifyCode)){ //校验失败 getRequest().setAttribute("errorMsg","验证码校验失败"); return "forward:/login/login.jsp"; } //4、校验成功,继续进行登录校验【无代码,直接向后运行】 //二、再进行用户登录校验 //1、接收表单参数 User param = toBean(User.class); //2、调用service进行登录处理 User result = null; try { result = userService.login(param); } catch (Exception e) { //抛出异常,登录也是失败 getRequest().setAttribute("errorMsg",e.getMessage()); return "forward:/login/login.jsp"; } //3、根据返回结果,跳转不同的页面 if(result!=null){ //登录成功 getRequest().getSession().setAttribute("loginUser",result); //三、判断用户是否需要记住用户名 //1、尝试从请求中获取remember参数 String rememberStr = getRequest().getParameter("remember"); //2、判断remember参数,如果remember不为null,记住用户名 if(rememberStr!=null){ Cookie remember = new Cookie("remember", URLEncoder.encode(result.getLoginName(), "utf-8")); remember.setPath(getRequest().getContextPath()); remember.setMaxAge(60*60*24*7); getResponse().addCookie(remember); }else{ //3、remember为null,删除之前记住的用户名 Cookie remember = new Cookie("remember", ""); remember.setPath(getRequest().getContextPath()); remember.setMaxAge(0); getResponse().addCookie(remember); } return "redirect:/index.jsp"; }else{ //登录失败 getRequest().setAttribute("errorMsg","用户名或密码错误"); return "forward:/login/login.jsp"; } }
优化UserServlet
/** * 用户登录 * @return */ public String login() throws UnsupportedEncodingException { //一、先进行验证码校验 //1、分别获取表单验证码和正确验证码 String verifyCode = getRequest().getParameter("verifyCode"); String vci = (String) getRequest().getSession().getAttribute("vci"); //2、为了防止被重复校验验证码,正确验证码使用一次,就要从session中消除 getRequest().getSession().removeAttribute("vci"); //3、校验判断,若校验失败,直接返回错误信息,不用进行用户登录判断 //若用户未提交验证码 或者 正确验证码不存在 或者 两个验证码不同 ABCD和 abcd 相同 if(verifyCode==null || vci==null || !vci.equalsIgnoreCase(verifyCode)){ //校验失败 getRequest().setAttribute("errorMsg","验证码校验失败"); return "forward:/login/login.jsp"; } //4、校验成功,继续进行登录校验【无代码,直接向后运行】 //二、再进行用户登录校验 //1、接收表单参数 User param = toBean(User.class); //2、调用service进行登录处理 User result = null; try { result = userService.login(param); } catch (Exception e) { //抛出异常,登录也是失败 getRequest().setAttribute("errorMsg",e.getMessage()); return "forward:/login/login.jsp"; } //3、根据返回结果,跳转不同的页面 if(result!=null){ //登录成功 getRequest().getSession().setAttribute("loginUser",result); //三、判断用户是否需要记住用户名 //1、尝试从请求中获取remember参数 String rememberStr = getRequest().getParameter("remember"); //2、判断remember参数,如果remember不为null,记住用户名 Cookie remember = new Cookie("remember", ""); remember.setPath(getRequest().getContextPath()); if(rememberStr!=null){ remember.setValue(URLEncoder.encode(result.getLoginName(), "utf-8")); remember.setMaxAge(60*60*24*7); }else{ //3、remember为null,删除之前记住的用户名 remember.setMaxAge(0); } getResponse().addCookie(remember); return "redirect:/index.jsp"; }else{ //登录失败 getRequest().setAttribute("errorMsg","用户名或密码错误"); return "forward:/login/login.jsp"; } }
//cookie数据回显: (用户名,复选框)
/login/login.jsp
<% //1、从cookie中获取用户名 //1.1、获取cookie数组 Cookie[] arr = request.getCookies(); //1.2、遍历数组,寻找记录用户名cookie,取出value值 String rememberUsername = "";//为了在展示JSP时,不存在记录的用户名不能展示null,不利于用户体现 if(arr!=null){ for (Cookie c : arr) { if(c.getName().equals("remember")){ rememberUsername = URLDecoder.decode(c.getValue(),"utf-8"); break; } } } %> <tr> <td height="30" nowrap> <font color="000F60"><strong>用户名:</strong> </font> </td> <td> <input type="text" name="loginName" class="test" style="width: 160px;" value="<%=rememberUsername%>"/> </td> </tr> <tr> <td height="30" nowrap> </td> <td> <input type="checkbox" name="autoLogin" value="yes"/>自动登录 <input type="checkbox" name="remember" value="yes" <% //用户名不是空字符串,说明之前用户 记录用户名,框体就应该被回显选中 if(!rememberUsername.equals("")){ out.write("checked='checked'"); } %> />记住用户名 </td> </tr>
10、UMS-MD5校验【扩展】
10.1、需求说明
密码 敏感数据可能存在泄露和丢失
担心:保存在服务器上会不会泄露
拷贝走数据(非项目组成员)
不道德程序员,记录下来
对敏感数据,例如密码进行加密操作。
public static void main(String[] args) { //因为加密算法是固定的,对同一个数据加密两次,加密结果是相同的 String str = "沈洋洋"; String md5 = UMSUtils.getMD5(str); System.out.println(md5);//f7370f7dc09f3ab88ea1d81283fb725f String md52 = UMSUtils.getMD5(str); System.out.println(md52);//f7370f7dc09f3ab88ea1d81283fb725f }
10.2、需求分析
添加用户:输入用户密码进行保存,对密码进行md5加密
编辑用户:密码回显和修改,对修改密码进行md5加密
用户登录:对表单输入的密码进行md5加密
10.3、代码修改
添加用户:
UserService
/** * 添加用户 * @param param * @return */ public boolean addUser(User param) { //1、生成随机ID param.setId(UUID.randomUUID().toString().replaceAll("-","")); //敏感数据进行MD5加密 param.setLoginPwd(UMSUtils.getMD5(param.getLoginPwd())); //2、调用Dao进行数据保存 //3、try...catch对处理结果进行判断:没有出现异常,保存成功,否则保存失败 try { userDao.addUser(param); } catch (Exception e) { //出现异常,添加失败 return false; } //没有出现异常,添加成功 return true; }
编辑用户:
可能性:
加密密码回显表单后,用户没有对加密密码进行过任何修改,加密密码不要被再次加密
加密密码回显表单后,用户对加密密码进行过修改,对密码进行重新加密
解决:
在页面添加一个隐藏域:pwdSource 源密码(加密密码)
servlet、service进行判断:
如果表单密码框数据 == 源密码,说明用户未对密码进行修改,不需要对表单密码进行再次加密
如果表单密码框数据 != 源密码,说明用户一定对密码进行了修改,需要对表单密码进行再次加密。
BUG:用户新改的密码 和 md5源加密密码一致,无法判断。
edit.jsp
<form method="post" action="<%=pageContext.getServletContext().getContextPath()%>/user"> <input type="hidden" name="method" value="modifyUser" /> <input type="hidden" name="id" value="${user.id}" /> <input type="hidden" name="pwdResource" value="${user.loginPwd}" />
UserServlet
/** * 修改用户信息 * @return */ public String modifyUser(){ //获取源密码 String pwdResource = getRequest().getParameter("pwdResource"); //1、获取所有表单数据 User param = toBean(User.class); //2、调用service进行保存 boolean result = userService.modifyUser(param,pwdResource); //3、根据service保存结果,进行展示 if(result){ //修改成功 return "redirect:/user?method=list"; }else{ //修改失败 getRequest().setAttribute("errorMsg","修改失败"); return "forward:/user/error.jsp"; } }
UserService
/** * 修改用户信息 * @param param * @param pwdResource * @return */ public boolean modifyUser(User param, String pwdResource) { try { //1、查询所有用户信息 List<User> ulist = userDao.searchAll(); //2、迭代删除被修改的用户 if(ulist!=null){ Iterator<User> it = ulist.iterator(); while (it.hasNext()){ User next = it.next(); if(next.getId().equals(param.getId())){ it.remove(); break; } } } //在向ulist追加之前,要对密码进行处理,用户表单密码到底要不要加密 //表单密码==源密码,说明用户未修改,不要再次加密(无代码) //表单密码!=源密码,说明用户已修改,需要再次加密 if(!param.getLoginPwd().equals(pwdResource)){ param.setLoginPwd(UMSUtils.getMD5(param.getLoginPwd())); } //3、向集合追加被修改用户的新信息 ulist.add(param); //4、以覆盖方式写回xml userDao.saveUlist(ulist); } catch (Exception e) { return false; } return true; }
LoginServlet
/** * 用户登录。 用户登录成功,返回User对象。 登录失败,返回Null * @param param * @return */ public User login(User param) { //对表单密码进行加密 param.setLoginPwd(UMSUtils.getMD5(param.getLoginPwd())); //1、获取所有用户信息 List<User> ulist = userDao.searchAll(); //2、遍历所有用户信息 if(ulist!=null){ for (User u : ulist) { //3、每遍历一个用户信息,对比表单用户名是否正确,对比表单密码是否正确. 都正确,登录成功 if(u.getLoginName().equals(param.getLoginName()) && u.getLoginPwd().equals(param.getLoginPwd())){ return u; } } } //4、经过遍历,没有一个成功,登录失败 return null; }