Java Web 登录采用非对称加密(RSA算法)+单例模式+redis+登录锁定5次
通过单例生成公钥和私钥(单例生成的好处除了优化程序外,也可以防止多IP登录造成干扰),前台只接受明文,由redis保存,每次登录失败、退出等只要是跳转到登录页面的都要将明文传过来。
在这里封装成一个方法:getRsaKey()
public RSAPrivateKey getRsaKey() throws NoSuchAlgorithmException{
//判断redis中有就不再生成,没有就再生成一次
RSAPrivateKey key = RedisCluster.use().get("privateKey");
if(key==null){
HashMap<String, Object> map = RSAUtils.getKeys();
//生成公钥和私钥
RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
//私钥保存在session中,用于解密
//公钥信息保存在页面,用于加密
String publicKeyExponent = publicKey.getPublicExponent().toString(16);
String publicKeyModulus = publicKey.getModulus().toString(16);
RedisCluster.use().set("privateKey", privateKey);
RedisCluster.use().set("publicKeyExponent", publicKeyExponent);
RedisCluster.use().set("publicKeyModulus", publicKeyModulus);
}
return null;
}在加载登录页面前执行该方法:
public void index() throws NoSuchAlgorithmException {
this.getRsaKey();
JSession jsession = getJSession();
logger.info("jsession=" + jsession);
logger.info("USER_FLAG=" + jsession.getAttribute(BaseConst.USER_FLAG));
if (jsession == null
|| jsession.getAttribute(BaseConst.USER_FLAG) == null) {
setAttr("publicKeyExponent", RedisCluster.use().get("publicKeyExponent"));
setAttr("publicKeyModulus", RedisCluster.use().get("publicKeyModulus"));
render("login.jsp");
} else {
render("index.jsp");
}
}登录页面,RSA对密码解密,md5加密(后台存密文),登录5次会锁定,每次登录错误提示剩余次数(解锁走定时任务),只要是跳转到登录页面的都要将明文传过来,逻辑可看注释:
/**
* 登录
* @throws Exception
*/
@Unauth
@Before({FormValidator.class,LoginValidator.class})
public void login() throws Exception {
LoginInfo loginInfo = new LoginInfo();
Des desObj = new Des();
loginInfo.set("uuid", ToolKit.getUuidByJdk(true));
loginInfo.set("logn_time", DateKit.getCurrentDate("yyyy-MM-dd HH:mm:ss"));
loginInfo.set("logn_ip", WebKit.getIpAddr(this.getRequest()));
String loginname = getPara("loginname");
loginInfo.set("user_id",loginname);
String desPasswd = getPara("despasswd");
System.out.println(desPasswd);
String logPsw =null;
//非对称解密
JSession jsession = getJSession();
RSAPrivateKey rawPasswd = (RSAPrivateKey)RedisCluster.use().get("privateKey");
if(rawPasswd!=null){
long time1 = System.currentTimeMillis();
logPsw = RSAUtils.decryptByPrivateKey(desPasswd, rawPasswd);
}
//md5加盐加密
String loginPsw = PasswdUtils.crypt(logPsw);
logger.info("user login, loginname=" + loginname + ",passwd="
+ loginPsw);
//每次登录时,已经锁定直接禁止登录
Record isLocked = UserService.me.isLocked(loginname);
if (isLocked != null) {
setAttr("validateAuthCodeFailed", "密码输入错误已超过上限,请于24小时之后重新登录");
setAttr("publicKeyExponent",RedisCluster.use().get("publicKeyExponent"));
setAttr("publicKeyModulus",RedisCluster.use().get("publicKeyModulus"));
render("login.jsp");
return;
}
//没有锁定就判定,如果失败就把失败次数+1,如果成功就重新置0
//失败次数+1后判断失败次数是否是5,是5的话将锁定标志置为真,并设上时间。
User huser = User.me.findFirst("SELECT * FROM hp_user where username = ?", loginname);
if (huser == null) {
setAttr("validateAuthCodeFailed", "用户名或密码错误");
setAttr("publicKeyExponent",RedisCluster.use().get("publicKeyExponent"));
setAttr("publicKeyModulus",RedisCluster.use().get("publicKeyModulus"));
render("login.jsp");
return;
}
Record user = UserService.me.login(loginname, loginPsw);
if (user == null) {
logger.info("user login error, 用户名或密码错误, loginname=" + loginname
+ ",passwd=" + loginPsw);
loginInfo.set("login_status", "1");
loginInfo.set("login_msg", "用户名或密码错误");
loginInfo.save();
huser.set("failure_time", String.valueOf(Integer.parseInt((String) huser.get("failure_time"))+1) );
setAttr("validateAuthCodeFailed", "用户名或密码错误,你还有"+Integer.toString(5-Integer.parseInt((String) huser.get("failure_time")))+"次尝试机会");
if("5".equals(huser.get("failure_time"))){
Date date=new Date();//取时间
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(calendar.DATE,1);//把日期往后增加一天.整数往后推,负数往前移动
date=calendar.getTime(); //这个时间就是日期往后推一天的结果
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String lock_time = formatter.format(date);
huser.set("lock_sign", "1");
huser.set("lock_time", lock_time);
setAttr("validateAuthCodeFailed", "密码输入错误已超过上限,请于24小时之后重新登录");
}
huser.update();
setAttr("publicKeyExponent",RedisCluster.use().get("publicKeyExponent"));
setAttr("publicKeyModulus",RedisCluster.use().get("publicKeyModulus"));
render("login.jsp");
return;
}前台js:为方便对提交数据进行修改,将form直接提交方法改成 onsubmit="return loadNow()"
<form id="formsmill" name="formsmill" action="${ctx}/application/login" method="post" enctype="multipart/form-data" onsubmit="return loadNow()">
<input type="hidden" id="publicKeyExponent" value="${publicKeyExponent}" />
<input type="hidden" id="publicKeyModulus" value="${publicKeyModulus}" />
</form> function loadNow(){
debugger
//待加密字符串
var orgPwd = $("#passwd").val();
var publicKeyExponent = $("#publicKeyExponent").val();
var publicKeyModulus = $("#publicKeyModulus").val();
RSAUtils.setMaxDigits(200);
var key = new RSAUtils.getKeyPair(publicKeyExponent, "", publicKeyModulus);
var encrypedPwd = RSAUtils.encryptedString(key,orgPwd.split("").reverse().join(""));
$("#despasswd").val(encrypedPwd);
$("#passwd").val(encrypedPwd);
var params = $("#formsmill").serialize();
$("#formsmill").attr("action","${ctx}/application/login?"+params);
}对于RSA加密逻辑,可以看上篇文章声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: Vue.js实现表格渲染
- 下一篇: java web登录RSA加密
