登录这个功能,是不管哪个项目都会用到的,登录做的好坏,安全性的保障将直接影响到整个系统的成败,尤其是一些安全性要求比较严格的项目,下面跟我一起来看一下这里是怎么做的
首先需要对密码进行加密,这里用到的是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="请输入手机号/用户名/邮箱" οnkeyup="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="请输入密码" οnkeyup="value=value.replace(/\s/g,'')" style="display: none;width:280px">
<input type="password" class="password1" id="pass1" name="password1" maxlength="16" autocomplete="off" placeholder="请输入密码" οnkeyup="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:" οnclick="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.οnkeydοwn=keyListener;
function keyListener(e){
// 当按下回车键,执行我们的代码
if(e.keyCode == 13){
document.getElementById("loginOnclick").onclick();
}
}
</script>
</body>
</html>
再来看一下这个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");
}
}
上面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;
}
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);
}
登录这块还要很多功能在这里就不细说了,我主要是觉得这里的加密和检验工作做得比较好,记录一下,方便以后的使用和学习。