| @@ -0,0 +1,177 @@ | |||
| package com.lion.config; | |||
| import com.lion.entity.LoginUserInfo; | |||
| import com.lion.util.PropertiesUtil; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.apache.commons.lang3.time.DateFormatUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.util.Date; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| // zhao@20230427: 用户登录失败记录缓存 | |||
| public final class UserLoginRecordCache | |||
| { | |||
| private static final Logger logger = LoggerFactory.getLogger(UserLoginRecordCache.class); | |||
| public static final Map<String, LoginUserInfo> cache = new HashMap<>(); | |||
| private static Integer FAIL_COUNT_LIMIT; | |||
| private static Integer FAIL_LIMIT_TIME; | |||
| private static boolean inited = false; | |||
| private static void Init() | |||
| { | |||
| if(inited) | |||
| return; | |||
| FAIL_COUNT_LIMIT = ParseInt(PropertiesUtil.getProperty("USER_LOGIN.FAIL_COUNT_LIMIT")); | |||
| FAIL_LIMIT_TIME = ParseInt(PropertiesUtil.getProperty("USER_LOGIN.FAIL_LIMIT_TIME")); | |||
| inited = true; | |||
| } | |||
| private static int ParseInt(String val) | |||
| { | |||
| if(StringUtils.isEmpty(val)) | |||
| return 0; | |||
| try | |||
| { | |||
| return Integer.parseInt(val); | |||
| } | |||
| catch(Exception e) | |||
| { | |||
| e.printStackTrace(); | |||
| return 0; | |||
| } | |||
| } | |||
| public static String BeginUserLogin(String userId) | |||
| { | |||
| Init(); | |||
| synchronized(cache) { | |||
| long time; | |||
| LoginUserInfo user; | |||
| if(FAIL_COUNT_LIMIT <= 0) | |||
| return null; | |||
| if(!cache.containsKey(userId)) // 未登录过 | |||
| { | |||
| user = new LoginUserInfo(); | |||
| user.setUserAccount(userId); | |||
| user.LoginFailCount(0); | |||
| user.LoginFailPunishStartTime(0); | |||
| cache.put(userId, user); | |||
| LOG("用户 {} 从未登录", userId); | |||
| return null; | |||
| } | |||
| else | |||
| user = cache.get(userId); | |||
| if(FAIL_LIMIT_TIME > 0) | |||
| { | |||
| time = System.currentTimeMillis(); | |||
| long loginFailPunishStartTime = user.LoginFailPunishStartTime(); | |||
| if(loginFailPunishStartTime > 0) // 锁定中 | |||
| { | |||
| if(time - loginFailPunishStartTime > FAIL_LIMIT_TIME * 1000) // 过了锁定时间 | |||
| { | |||
| LOG("用户 {} 登录锁定中且过了锁定时间: {} - {} > {}秒", userId, date_format(time), date_format(loginFailPunishStartTime), FAIL_LIMIT_TIME); | |||
| user.LoginFailPunishStartTime(0); | |||
| user.LoginFailCount(0); | |||
| return null; | |||
| } | |||
| else // 还在锁定时间 | |||
| { | |||
| LOG("用户 {} 登录锁定中: {} - {} <= {}秒", userId, date_format(time), date_format(loginFailPunishStartTime), FAIL_LIMIT_TIME); | |||
| return "该用户登录失败已超过限制次数, 锁定登录中"; | |||
| } | |||
| } | |||
| else // 未锁定 | |||
| { | |||
| if(user.LoginFailCount() >= FAIL_COUNT_LIMIT) // 超过限制 | |||
| { | |||
| user.LoginFailPunishStartTime(time); | |||
| LOG("用户 {} 锁定登录: {}", userId, date_format(time)); | |||
| return "该用户登录失败已超过限制次数, 将锁定登录"; | |||
| } | |||
| else // 还有次数 | |||
| { | |||
| LOG("用户 {} 允许登录: {} < {}", userId, user.LoginFailCount(), FAIL_COUNT_LIMIT); | |||
| return null; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| return null; | |||
| } | |||
| } | |||
| public static boolean EndUserLogin(String userId, boolean success) | |||
| { | |||
| synchronized(cache) { | |||
| long time; | |||
| LoginUserInfo user; | |||
| if(FAIL_COUNT_LIMIT <= 0) | |||
| return false; | |||
| user = cache.get(userId); | |||
| if(success) // 登录成功清空失败记录 | |||
| { | |||
| LOG("用户 {} 登录成功", userId); | |||
| user.LoginFailPunishStartTime(0); | |||
| user.LoginFailCount(0); | |||
| return false; | |||
| } | |||
| time = System.currentTimeMillis(); | |||
| user.LoginFailCount(user.LoginFailCount() + 1); | |||
| if(FAIL_LIMIT_TIME > 0) | |||
| { | |||
| if(user.LoginFailCount() >= FAIL_COUNT_LIMIT) // 超过失败次数 | |||
| { | |||
| LOG("用户 {} 超出登录失败次数, 开始锁定: {} >= {}", userId, user.LoginFailCount(), FAIL_COUNT_LIMIT); | |||
| user.LoginFailPunishStartTime(time); // 锁定 | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| LOG("用户 {} 登录失败剩余次数 {}", userId, FAIL_COUNT_LIMIT - user.LoginFailCount()); | |||
| user.LoginFailPunishStartTime(0); // 不锁定 | |||
| return false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| user.LoginFailPunishStartTime(0); | |||
| if(user.LoginFailCount() >= FAIL_COUNT_LIMIT) | |||
| user.LoginFailCount(0); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| private static String date_format(long ts) | |||
| { | |||
| return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd HH:mm:ss-SSS"); | |||
| } | |||
| private static void LOG(Object obj, Object...args) | |||
| { | |||
| if(null == obj) | |||
| logger.info("NULL"); | |||
| else | |||
| { | |||
| if(obj instanceof String) | |||
| { | |||
| logger.info((String)obj, args); | |||
| } | |||
| else | |||
| { | |||
| logger.info(obj.toString()); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -17,6 +17,22 @@ public class LoginUserInfo { | |||
| private String userAccount ;//登录账号 | |||
| private String roleid; | |||
| private String orgid; | |||
| // zhao@20230427 | |||
| private long loginFailPunishStartTime; // 登录失败惩罚开始时间 | |||
| private int loginFailCount; // 登录失败次数 | |||
| public long LoginFailPunishStartTime(long...l) | |||
| { | |||
| if(null != l && l.length > 0) | |||
| loginFailPunishStartTime = l[0]; | |||
| return loginFailPunishStartTime; | |||
| } | |||
| public int LoginFailCount(int...i) | |||
| { | |||
| if(null != i&& i.length > 0) | |||
| loginFailCount = i[0]; | |||
| return loginFailCount; | |||
| } | |||
| public String getUserId() { | |||
| return userId; | |||
| @@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import javax.servlet.http.HttpSession; | |||
| import com.lion.config.UserLoginRecordCache; | |||
| import org.apache.log4j.Logger; | |||
| import org.json.JSONObject; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| @@ -77,6 +78,11 @@ public class LoginService { | |||
| if(!code.equalsIgnoreCase(sessionCode)){ | |||
| return Util.responseString("false","验证码错误"); | |||
| } | |||
| String validateResult = UserLoginRecordCache.BeginUserLogin(userName); | |||
| if(null != validateResult) | |||
| return Util.responseString("false", validateResult); | |||
| try { | |||
| password = RasUtil.decrypt(password, private_key); | |||
| } catch (Exception e) { | |||
| @@ -91,6 +97,7 @@ public class LoginService { | |||
| String userId=list.get(0).get("id").toString(); | |||
| String roleId=list.get(0).get("roleid").toString();//角色id | |||
| if(StringUtil.isEmpty(roleId)){ | |||
| UserLoginRecordCache.EndUserLogin(userName, false); | |||
| return Util.responseString("false","该用户未分配角色,禁止登录"); | |||
| } | |||
| String cookie=MD5Util.StringInMd5(userId+TimeUtil.getNowTimeTwo()); | |||
| @@ -109,14 +116,18 @@ public class LoginService { | |||
| json.put("success","true"); | |||
| json.put("message",cookie); | |||
| json.put("orgid",list.get(0).get("orgid").toString()); | |||
| UserLoginRecordCache.EndUserLogin(userName, true); | |||
| return json.toString(); | |||
| }else{ | |||
| UserLoginRecordCache.EndUserLogin(userName, false); | |||
| return Util.responseString("false","登录失败"); | |||
| } | |||
| }else{ | |||
| UserLoginRecordCache.EndUserLogin(userName, false); | |||
| return Util.responseString("false","密码错误"); | |||
| } | |||
| } | |||
| UserLoginRecordCache.EndUserLogin(userName, false); | |||
| return Util.responseString("false","用户名或密码不存在"); | |||
| } | |||
| @@ -10,3 +10,7 @@ loginOut=http\://stage.huizhou.tydlxt.znxdcloud.com/api/user/logout | |||
| public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyAtzfkvb0EMNrlFNF1uYKYdtyYOVYUMfqWnAvRbE9XZoDlNUKqvKM8VfoNHrLBAe247iZW37+SiPqj28fztBJbEvbDOGLN0lINSyRac7v+MwSuNWGJAFE4/beM3vZz/21MDmbCReBbUSr1OBnLvzi9cPPSkaSN7trh1j/wwC559pUdhvf0MieJKwi0Q6k3NVpafszQw86r96LXfrL4GVk4OvXXIOKwFyNBgRJkWROz9L2DDJMebs4P4SJlLq+EeGRfAaOHzI8tEr/cOeiowM54z2g5BeM5xH28PpMlsx3FYXKwL+hJHs0+AQYyCt3ooPHJ4Q+7quVMOIB4Q+ATP6OQIDAQAB | |||
| #ras秘钥 | |||
| private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIC3N+S9vQQw2uUU0XW5gph23Jg5VhQx+pacC9FsT1dmgOU1Qqq8ozxV+g0essEB7bjuJlbfv5KI+qPbx/O0ElsS9sM4Ys3SUg1LJFpzu/4zBK41YYkAUTj9t4ze9nP/bUwOZsJF4FtRKvU4Gcu/OL1w89KRpI3u2uHWP/DALnn2lR2G9/QyJ4krCLRDqTc1Wlp+zNDDzqv3otd+svgZWTg69dcg4rAXI0GBEmRZE7P0vYMMkx5uzg/hImUur4R4ZF8Bo4fMjy0Sv9w56KjAznjPaDkF4znEfbw+kyWzHcVhcrAv6EkezT4BBjIK3eig8cnhD7uq5Uw4gHhD4BM/o5AgMBAAECggEBAKbxB30KiXKPwscKii9H/QALSQ+2g98bSTz0SCiE6/F80vHBkKfbnW7+9AMdrAilm1rXLxA+bN1NgDcuNjRnmsJ9z3mYtgySsP1pAy0llrNYQWD9v0fYSKQ+lYWHNpcPxklege0VnHFe3yz5n1zRbTnyS4Fa39iYUfnQBTc/Kt1nrZTXqL8cHPMUHyD9sYG40JLSc5Cnr6yPRZF0DSB93tvobvqk5Ao8QiP7durVfgkKULUfNZY0ChNZ0DYcVfYqiVk2iyvtcqWLsyykjfCTuOSukniVyEDLH+PZH/8eGw5trCKfSMDY9J1cQX7oBcc+DpGI1jacvWWkicsrFE3/wlECgYEA5kGbtdhVl+wUIn3JfJKOBfa21LD6/0O9WPJqWLblF82rdlA6wfmV6rFtgpDbibT3pz1hgjKvTioXuJ4dbT0Hh4VOHIYJCQ8bcqQMfyWYPLDRzPFwaITGAwztFcZ8QoaAYqAz9FXASaBzJtCD4CmAdvFl9rug7Q88i9ZvyAsI+18CgYEA3mkg258UNDh/cXnhyDXVZ5gpEJsbSyaJK0gToFelDP7loj3vFsyOw6qYTqI8zygGxznrGxW2+QS7YebQWVdERCjwdRnbRqAIqecAJiqygCIs+9DO8PPj8733B7t9c9+FQlSSIv2DXk7ZwTWzpHa6XmkCCBd1Mr2gYE4dgaiPiWcCgYA0/9MEh1gkUP3NdqCjIOS58LDiwh30FbaGu73Iz8hpsziNUihEL9vXGqH3VLqDtvjuMM2590qstjmhkBt74nlSM1fobt2zjRunRqVtusyQ465W+xgBptYhK5+CzJ4bffQdP3zV98r754e53nMMbOEZ/7SVl1iSWFh6Y5B1Pj0CBwKBgBgbzTQBSm9esHHchFzvePKBy/HA3nSG+Nd4OKho17tQ5hNwIzqVceRD2b6sV2sdK57s6E9HS04y9RznqC4HB59b0LTg2KQPNOE16Q46Ep9RFQ820zfLOCpzrRNpf2/QCuHlyPGCCXtvkKsg5xgsxob1WwMFh+64H2pRDWHAo86BAoGAfyD3Is5t6i8AmL/0W2Iq6qgT8C6ArmkiMZ4eXYX2Ko1MtjjAsRAcNJooC9/fTsRgNRe1EtR7a4jBzBvOISET9VAyhbGvLVNjFXdIn1oF4EqHlBXmk/D/G48+KOx8g4Z7bwzYL3cLPydhbGDoO2MHIPJlS07j8xGAgoVQGBTnWfw= | |||
| # ??????????????, 0??? | |||
| USER_LOGIN.FAIL_COUNT_LIMIT=5 | |||
| # ??????????????????, 0??? | |||
| USER_LOGIN.FAIL_LIMIT_TIME=90 | |||