登錄這個功能,是不管哪個項目都會用到的,登錄做的好壞,安全性的保障將直接影響到整個系統的成敗,尤其是一些安全性要求比較嚴格的項目
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;width: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;width: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); }
登錄這塊還要很多功能在這里就不細說了,我主要是覺得這里的加密和檢驗工作做得比較好,記錄一下,方便以后的使用和學習。