登录这个功能,是不管哪个项目都会用到的,登录做的好坏,安全性的保障将直接影响到整个系统的成败,尤其是一些安全性要求比较严格的项目
1.首先需要对密码进行加密,这里用到的是md5加密,需要在login.html所在页面引入jQuery.md5.js
<!DOCTYPE html> <html> <head> <title>登录页面</title> <meta http-equiv="content-Type" content="text/html" charset="utf-8"> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta name="keywords" content="XXXXXXXXXXX"/> <meta name="description" content="XXXXXXXXXXXXXXXXXXXXXX"/> <link rel="stylesheet" type="text/css" href="${ctxPath}/resources/css/login.css"> <link rel="stylesheet" type="text/css" href="${ctxPath}/resources/css/layer.css"> <script type="text/javascript" src="${ctxPath}/resources/js/JavaScript.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/jquery/jquery.min.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/jquery/jQuery.md5.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/validate.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/tab.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/newLoginDefault.js"></script> <script type="text/javascript"> var returnUrl='${returnUrl!}'; </script> <script type="text/javascript" src="${ctxPath}/resources/js/layer/layer.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/popwin.js"></script> <script type="text/javascript" src="${ctxPath}/resources/js/newlogin.js"></script> </head> <body> <input type="hidden" id="loginFrame" value="loginFrame"> <input type="hidden" id="rootPath" value="${ctxPath}"> <form id="login" action="" method="post" class="mainForm mainForm1" style="display:block"> <!-- <img src="${ctxPath}/resources/images/guanbi.png" id="close" alt="" /> --> <div class="container"> <div class="number"> <span>登录<span> </div> <div class="normalInput"> <input type="text" class="phone" id="phone" name="phone" onBlur="CheckEmpty()" placeholder="请输入手机号/用户名/邮箱" onkeyup="value=value.replace(/s/g,'')"> <input id="sign" name="sign" type="hidden"/> </div> <span class="error error1"></span> <span class="error error2"></span> <div class="normalInput"> <input type="text" class="password" id="pass" name="password" maxlength="16" autocomplete="off" placeholder="请输入密码" onkeyup="value=value.replace(/s/g,'')" style="display: none;280px"> <input type="password" class="password1" id="pass1" name="password1" maxlength="16" autocomplete="off" placeholder="请输入密码" onkeyup="value=value.replace(/s/g,'')" style="display: inline-block;280px"> <input hidden="hidden" type="text" id="hiddenPass"/> <a id="pwdBtn" href="##" class="pwdBtnShow" isshow="true"> <i class="i_icon" style="background-position: -60px -93px;"></i> </a> </div> <span class="error error3"></span> <a id="loginOnclick" href="javascript:" onclick="login(0)" class="fullBtnBlue">登录</a> <a target="_Blank" href="${ctxPath}/toRestpwds.htm" class="forget">忘记密码?</a> </div> <p>还没有账号? <a href="#" class="register">免费注册</a></p> </form> <script> $("#close").click(function(){ $(".mainForm1").hide(); }) $('.register').unbind(); $('.register').click(function(){ var index = parent.layer.getFrameIndex(window.name); parent.layer.open({ type: 2, title: '', shadeClose: false, shade: 0.5, area: ['445px','374px'], content: '${request.contextPath}/registers.htm' }); parent.layer.close(index); }); //为keyListener方法注册按键事件 document.onkeydown=keyListener; function keyListener(e){ // 当按下回车键,执行我们的代码 if(e.keyCode == 13){ document.getElementById("loginOnclick").onclick(); } } </script> </body> </html>
2.再来看一下这个newlogin.js,注意对输入手机号和密码的加密(md5加密),hiddenPass和sign,从安全性来说这里是值得借鉴的,其他的代码也一并粘出来吧,方便以后学习和借鉴。
function login(num){ // $("#l_tips").attr("style","display:block"); // $("#logMsg").html("密码不能为空!"); reg1=/^.*[d]+.*$/; reg2=/^.*[A-Za-z]+.*$/; reg3=/^.*[_@#%&^+-/*/\]+.*$/;//验证密码 if($(".pwdBtnShow").attr("isshow")=="false") { var Pval = $(".password").val(); } else { var Pval = $(".password1").val(); } if( Pval =="") { $(".password").parent().addClass("errorC"); $(".error3").html("请填写密码!"); $(".error3").css("display","block"); $(".error1").css("display","none"); $(".error2").css("display","none"); return false; } //注册具体方法 // var PWD = $(".password").val().trim(); // var PWD1 = $(".password1").val().trim(); // if(PWD.length >= PWD1.length){ // $("#hiddenPass").val($.md5(PWD)); // }else{ // $("#hiddenPass").val($.md5(PWD1)); // } $("#hiddenPass").val($.md5(Pval)); $("#sign").val($.md5($("#phone").val()+$("#hiddenPass").val())); var flag=''; if(null!=$("#flag").val()){ flag="?flag="+$("#flag").val(); } $("#loginOnclick").html("登录中..."); $('#loginOnclick').css('background-color','#ccc'); $('#loginOnclick').removeAttr('onclick'); if(num==0){ $.ajax({ type : "POST", url : "ssl/logins.htm", dataType : "json", async : false, data:{ "j_password" : $("#hiddenPass").val(), "j_username" : $("#phone").val(), "sign" : $("#sign").val(), "afs_scene":$("#afs_scene").val(), "afs_token":$("#afs_token").val(), }, success : function(data) { var pathName=window.document.location.pathname; var projectName=pathName.substring(0,pathName.substr(1).indexOf('/')+1); if(projectName!="/puhuilicai"){ projectName=""; } if (data.msg == 2){//成功返回 if(data.isRisk=='yes'){//进行风险拦截 $("iframe",window.parent.document).attr("src",projectName+"/toLogins.htm"); }else{ if(data.isFirstLogin=='no'){//登录送奖励 判断是否当天第一次登录 if(window.top==window.self){ //不存在父页面 window.location.href="https://www.baidu.com"; }else{ if(returnUrl!=''){//未登录情况下请求拦截页面 var index = parent.layer.getFrameIndex(window.name); parent.location.href=returnUrl; parent.layer.close(index); }else{ //mxl var aa=window.parent.location + ''; if(aa.indexOf('toRestpwd.htm') == -1 && aa.indexOf('toRestpwds.htm') == -1 && aa.indexOf('toRestpwd2.htm') == -1 && aa.indexOf('toRestpw3.htm') == -1 //&& aa.indexOf('toRestpw4.htm') == -1 ){ //提示层 parent.location.reload(); } else{ //parent.location.href="https://www.baidu.com"; parent.location.href="index.htm"; var index = parent.layer.getFrameIndex(window.name); parent.layer.close(index); } } } }else{//第一次登录当奖励窗口 //mxl var aa=window.parent.location + ''; if(aa.indexOf('toRestpwd.htm') == -1 && aa.indexOf('toRestpwds.htm') == -1 && aa.indexOf('toRestpwd2.htm') == -1 && aa.indexOf('toRestpw3.htm') == -1 //&& aa.indexOf('toRestpw4.htm') == -1 ){ //提示层 var voucherName=data.voucherName.replace("%","*"); var index = parent.layer.getFrameIndex(window.name); parent.$("#frame_top").load(projectName+"/frame_top.htm"); popWin.showWin("880","840","xxxx",projectName+"/ssl/loginSuccess.htm?integral="+data.integral+"&totalIntegral="+data.totalIntegral+"&loginDays="+data.loginDays+"&voucherName="+voucherName); parent.layer.close(index); } else{ //parent.location.href="https://www.baidu.com"; parent.location.href="index.htm"; var index = parent.layer.getFrameIndex(window.name); parent.layer.close(index); } } } }else if(data.msg==1){ if(data.isRisk=='yes'){//进行风险拦截 $("iframe",window.parent.document).attr("src",projectName+"/toLogins.htm"); }else{ if(data.isFirstLogin=='no'){//登录送奖励 判断是否当天第一次登录 if(window.top==window.self){ //不存在父页面 window.location.href="https://www.baidu.com"; }else{ if(returnUrl!=''){//未登录情况下请求拦截页面 var index = parent.layer.getFrameIndex(window.name); parent.location.href=returnUrl; parent.layer.close(index); }else{ parent.location.reload(); } } }else{//第一次登录当奖励窗口 var voucherName=data.voucherName.replace("%","*"); var index = parent.layer.getFrameIndex(window.name); parent.$("#frame_top").load(projectName+"/frame_top.htm"); popWin.showWin("880","840","普惠理财",projectName+"/ssl/loginSuccess.htm?integral="+data.integral+"&totalIntegral="+data.totalIntegral+"&loginDays="+data.loginDays+"&voucherName="+voucherName); parent.layer.close(index); } } }else if(data.msg==-1){ // $("#loginPhone").text("账号不存在"); // $("#phone").val(""); // $("#pass").val(""); $(".phone").parent().removeClass("checkedN"); $(".phone").parent().addClass("errorC"); $(".error1").html("账号不存在"); $(".error1").css("display","block"); $(".error2").css("display","none"); $(".error3").css("display","none"); $("#loginOnclick").html("登录"); $('#loginOnclick').css('background-color','#ed5345'); $('#loginOnclick').attr('onclick','login(0)'); }else{ // $("#loginPass").text("用户名或密码不正确!"); // $("#pass").val(""); $(".password").parent().addClass("errorC"); $(".error3").html("用户名或密码不正确!"); $(".error3").css("display","block"); $(".error1").css("display","none"); $(".error2").css("display","none"); $("#loginOnclick").html("登录"); $('#loginOnclick').css('background-color','#ed5345'); $('#loginOnclick').attr('onclick','login(0)'); } } }); }else{ $.ajax({ type : "POST", url : "ssl/logins.htm", dataType : "json", async : false, data:{ "j_password" : $("#pass").val(), "j_username" : $("#phone").val(), "sign" : $("#sign").val(), "sig":$("#sig").val(), "token":$("#token").val(), "sessionId":$("#sessionId").val() }, //data : $('#form').serialize(), success : function(data) { var pathName=window.document.location.pathname; var projectName=pathName.substring(0,pathName.substr(1).indexOf('/')+1); if(projectName!="/puhuilicai"){ projectName=""; } if (data.msg == 2){ if(data.isRisk=='yes'){//进行风险拦截 $("iframe",window.parent.document).attr("src",projectName+"/toLogins.htm"); }else{ if(data.isFirstLogin=='no'){ if(window.top==window.self){ //不存在父页面 window.location.href="https://www.baidu.com"; }else{ if(returnUrl!=''){ var index = parent.layer.getFrameIndex(window.name); parent.location.href=returnUrl; parent.layer.close(index); }else{ parent.location.reload(); } } }else{ var voucherName=data.voucherName.replace("%","*"); var index = parent.layer.getFrameIndex(window.name); popWin.showWin("880","840","xxxx",projectName+"/ssl/loginSuccess.htm?integral="+data.integral+"&totalIntegral="+data.totalIntegral+"&loginDays="+data.loginDays+"&voucherName="+voucherName); parent.layer.close(index); } } }else if(data.msg==1){ window.location.href="ssl/account/toEntCenter.htm"; }else if(data.msg==-1){ $("#loginPhone").text("账号不存在"); $("#phone").val(""); $("#pass").val(""); }else{ $("#loginPass").text("用户名或密码不正确!"); $("#pass").val(""); } } }); } return false; } function CheckEmpty(){ if($.trim($("#phone").val())==""){ //$("#loginPhone").text("账号不能为空"); $(".phone").parent().addClass("errorC"); $(".error1").html("账号不能为空"); $(".error1").css("display","block"); $(".error2").css("display","none"); $(".error3").css("display","none"); return false; }else{ //$("#loginPhone").text(""); $(".phone").parent().addClass("checkedN"); } }
3.上面js中手机号和密码加密得到的sign有什么用呢,下面在Controller中看一下
@ResponseBody @RequestMapping(value="/ssl/logins",method = RequestMethod.POST) public Map<String, String> logins(String afs_scene,String afs_token,String sig,String sessionId,String token,String sign,String j_username,String j_password,HttpServletRequest request,HttpSession session){ CustUser custUser = null; Map<String,String> map = new HashMap<String, String>(1); String flag = "0"; //失败 //连续登录天数 String loginDays = "1"; //增加的积分数 String integral ="0"; //是否每天第一次登录 String isFirstLogin ="yes"; //卡券名称 String voucherName ="0.1% 加息券"; //是否风险用户 String isRisk="no"; try{ if(signValidate(j_username,j_password,sign)){ custUser = userRegisterService.getCustUserByAccountAndPassowd(j_username.toLowerCase().trim(),j_password); if(custUser!=null){ flag = custUser.getCustType().toString(); if("no".equals(isRisk)){ Long loginTime =null; CustUserLogin custUserLogin = userRegisterService.getLastLoginTime(custUser.getId()); //判断是否每天第一次登录 Map<String,String> result = userRegisterService.saveFirstLoginHandle(request, custUser, custUserLogin); loginDays=result.get("loginDays"); isFirstLogin=result.get("isFirstLogin"); voucherName=result.get("voucherName"); loginTime = Long.valueOf(result.get("loginTime")); integral = result.get("integral"); custUser.setLoginTime(loginTime); if (custUser.getUserName().equals("")) { session.getServletContext().setAttribute(custUser.getMobile(),loginTime); }else{ session.getServletContext().setAttribute(custUser.getUserName(),loginTime); } //对存入数据库中的密码进行解密放到session中-zzj-2016-4-7 14:31:42 //custUser.setPassword(PassUtil.decode(custUser.getPassword())); session.setAttribute(Constants.USER,custUser); session.setAttribute(Constants.MOBILE_NUM,1); map.put("userId", custUser.getId().toString()); } Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\D])|(18[0-9]))\d{8}$"); Matcher m = p.matcher(custUser.getUserName()); if(m.matches()){ String phone = custUser.getUserName() ; phone = phone.substring(0,3) + "****" + phone.substring(7, phone.length()); session.setAttribute("userName", phone); }else{ session.setAttribute("userName", custUser.getUserName()); } }else{ if(null==userRegisterService.getCustUserByMobile(j_username.trim())) { flag = "-1"; } isFirstLogin="no"; } } }catch(Exception e){ logger.info(e.getMessage()); map.put("msg", "0"); return map; } //风险识别 map.put("isRisk",isRisk); map.put("msg", flag); map.put("isFirstLogin", isFirstLogin); map.put("loginDays", loginDays); map.put("integral", integral); if("yes".equals(isFirstLogin)){ map.put("totalIntegral", integralService.getIntegralByUserId(custUser.getId()).toString()); map.put("voucherName", voucherName); } return map; }
4.signValidate方法中,再一次对手机号和密码还要sign进行校验,具体看一下signValidate这个方法
/* 登录完整性验证 * @param sign * @return */ private boolean signValidate(String account,String password,String sign){ StringBuffer signInfo = new StringBuffer(); signInfo.append(account); signInfo.append(password); return sign.equals(DigestUtils.md5Hex(signInfo.toString())); }
public static String md5Hex(final byte[] data) { return Hex.encodeHexString(md5(data));
}
public static String encodeHexString(final byte[] data) { return new String(encodeHex(data)); } public static char[] encodeHex(final byte[] data) { return encodeHex(data, true); }
public static byte[] md5(final String data) { return md5(StringUtils.getBytesUtf8(data)); } public static byte[] getBytesUtf8(final String string) { return getBytes(string, Charsets.UTF_8); }
登录这块还要很多功能在这里就不细说了,我主要是觉得这里的加密和检验工作做得比较好,记录一下,方便以后的使用和学习。