Commit 18ed3477 authored by 技术部-任文超's avatar 技术部-任文超

1、代码重构; 2、删除临时接口clearOrLockIpv4(...)

parent 0850d3ca
......@@ -18,6 +18,7 @@ import cn.quantgroup.xyqb.model.UserStatistics;
import cn.quantgroup.xyqb.service.merchant.IMerchantService;
import cn.quantgroup.xyqb.service.session.ISessionService;
import cn.quantgroup.xyqb.service.sms.ISmsService;
import cn.quantgroup.xyqb.service.user.ILockIpv4Service;
import cn.quantgroup.xyqb.service.user.IUserDetailService;
import cn.quantgroup.xyqb.service.user.IUserService;
import cn.quantgroup.xyqb.service.wechat.IWechatService;
......@@ -54,6 +55,9 @@ public class UserController implements IBaseController {
@Autowired
private IUserService userService;
@Autowired
private ILockIpv4Service lockIpv4Service;
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> stringRedisTemplate;
......@@ -87,50 +91,6 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult("", getCurrentUserFromRedis());
}
/**
* 解锁特定IP
* @param ip - 目标IP
* @param act - 操作标记,true-lock,false-unlock
* @param key - 密令
* @param request
* @return
*/
@RequestMapping("/lock_ipv4")
public JsonResult clearOrLockIpv4(@RequestParam(required = true)String ip,
@RequestParam(required = false)String act,
@RequestParam(required = true)String key,
HttpServletRequest request) {
if(!ValidationUtil.validateIpv4(ip) || StringUtils.isBlank(act) || StringUtils.isBlank(key)){
LOGGER.info("Fail to clear_or_lock ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
// 操作标记
boolean lock = Objects.equals(Boolean.TRUE.toString(), act);
String header_key = request.getHeader(Constants.IPV4_LOCK.replace(":", ""));
if(Objects.equals(Constants.CLEAR_LOCK_FOR_IPV4, header_key)){
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)", ValidationUtil.getMd5Key(lock));
}
boolean valid = ValidationUtil.isValid(key, lock);
if(!valid){
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR_OF_DAY);
valid = Objects.equals(Constants.CLEAR_LOCK_FOR_IPV4_KEY+hour, key);
}
if(valid){
String lockIpv4Key = getLockIpv4Key(ip);
if(lock){
stringRedisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), Constants.IPV4_FAILED_LOCK_MINUTES, TimeUnit.MINUTES);
LOGGER.info("Locked ip access:{}, error overstep {} times in {} minutes, do lock {} minutes", ip, Constants.IPV4_LOCK_ON_FAILED_COUNTS, Constants.IPV4_FAILED_COUNT_MINUTES, Constants.IPV4_FAILED_LOCK_MINUTES);
}else{
stringRedisTemplate.delete(lockIpv4Key);
LOGGER.info("Clear_or_lock ip Success:{}", ip);
}
return JsonResult.buildSuccessResult("Success",null);
}
LOGGER.info("Fail to clear_or_lock ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 登录(账号 + 密码)
* 密码错误达到限定次数时执行图形验证码校验
......@@ -546,11 +506,12 @@ public class UserController implements IBaseController {
} catch (UnsupportedEncodingException e) {
LOGGER.error("不支持的编码: ", e);
}
String clientIp = getIp();
String[] credentialArr = bufStr.split(":");
if (credentialArr.length != 2) {
LOGGER.info("用户登录失败:{}", bufStr);
// 向该ipv4添加错误计数器
countErrorByIpv4();
lockIpv4Service.countErrorByIpv4(clientIp);
return null;
}
String phoneNo = credentialArr[0];
......@@ -559,142 +520,24 @@ public class UserController implements IBaseController {
User user = userService.findByPhoneWithCache(phoneNo);
if (user == null || !user.getEnable()) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
lockIpv4Service.countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器
countErrorByIpv4();
lockIpv4Service.countErrorByIpv4(clientIp);
return null;
}
//验证密码
if (!validatePassword(pass, user.getPassword())) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
lockIpv4Service.countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器
countErrorByIpv4();
lockIpv4Service.countErrorByIpv4(clientIp);
return null;
}
// 向该ipv4添加成功计数器
countSuccessByIpv4();
lockIpv4Service.countSuccessByIpv4(clientIp);
return user;
}
/**
* 向该phoneNo添加错误计数器
* @param phoneNo
*/
private void countErrorByPhoneNo(String phoneNo) {
// 密码错误时,给该账号添加计数器
String key = Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
if (!stringRedisTemplate.hasKey(key)) {
LOGGER.info("添加错误计数器,key={}", key);
stringRedisTemplate.opsForValue().set(key, String.valueOf(0), DateUtils.getSeconds(), TimeUnit.SECONDS);
}
// 密码错误计数
Long errorCount = stringRedisTemplate.opsForValue().increment(key, 1L);
if (errorCount > Constants.Image_Need_Count) {
LOGGER.info("用户名或密码不正确,phoneNo={}", phoneNo);
throw new PasswordErrorLimitException("用户名或密码不正确");
} else if (Objects.equals(errorCount, Constants.Image_Need_Count)) {
LOGGER.info("请输入图形验证码,phoneNo={}", phoneNo);
throw new PasswordErrorLimitException("请输入图形验证码");
}
}
/**
* 向该ipv4添加错误计数器
*/
private void countErrorByIpv4() {
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){
return;
}*/
String ipv4 = getIp();
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getErrorIpKey(ipv4);
if(!stringRedisTemplate.hasKey(ipv4Key)){
// 计数周期1分钟
stringRedisTemplate.opsForValue().set(ipv4Key, String.valueOf(0), Constants.IPV4_FAILED_COUNT_MINUTES, TimeUnit.MINUTES);
}
Long count = stringRedisTemplate.opsForValue().increment(ipv4Key, 1L);
LOGGER.info("Lock_ipv4: count error ip access: ip={}, count={}", ipv4, count);
lockErrorIpv4(ipv4, count);
}
}
/**
* 锁定IPV4
* @param ip - 目标ip
* @param count - 错误计数
*/
private void lockErrorIpv4(String ip, long count){
// 每分钟计数阈值
long counts = Constants.IPV4_LOCK_ON_FAILED_COUNTS;
String redisCounts = stringRedisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisCounts) && Integer.valueOf(redisCounts) > 0){
counts = Integer.valueOf(redisCounts);
}
if(count < counts){
return;
}
// 锁定时长
long minutes = Constants.IPV4_FAILED_LOCK_MINUTES;
String redisMinutes = stringRedisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisMinutes) && Integer.valueOf(redisMinutes) > 0){
minutes = Integer.valueOf(redisMinutes);
}
String lockIpv4Key = getLockIpv4Key(ip);
stringRedisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), minutes, TimeUnit.MINUTES);
LOGGER.info("Lock_ipv4: locked error ip access:{}, error overstep {} times in {} minutes, do lock {} minutes", ip, counts, Constants.IPV4_FAILED_COUNT_MINUTES, minutes);
}
/**
* 向该phoneNo添加错误计数器
*/
private void countSuccessByIpv4() {
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){
return;
}*/
String ipv4 = getIp();
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getSuccessIpKey(ipv4);
if(!stringRedisTemplate.hasKey(ipv4Key)){
// 计数周期1分钟
stringRedisTemplate.opsForValue().set(ipv4Key, String.valueOf(0), Constants.IPV4_SUCCESS_COUNT_MINUTES, TimeUnit.MINUTES);
}
Long count = stringRedisTemplate.opsForValue().increment(ipv4Key, 1L);
LOGGER.info("Lock_ipv4: count success ip access: ip={}, count={}", ipv4, count);
lockSuccessIpv4(ipv4, count);
}
}
/**
* 锁定IPV4
* @param ip - 目标ip
* @param count - 错误计数
*/
private void lockSuccessIpv4(String ip, long count){
// 每小时计数阈值
if(count < Constants.IPV4_LOCK_ON_SUCCESS_COUNTS){
return;
}
// 锁定时长
String lockIpv4Key = getLockIpv4Key(ip);
stringRedisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), Constants.IPV4_SUCCESS_LOCK_MINUTES, TimeUnit.MINUTES);
LOGGER.info("Lock_ipv4: locked success ip access:{}, success overstep {} times in {} minutes, do lock {} minutes", ip, Constants.IPV4_LOCK_ON_SUCCESS_COUNTS, Constants.IPV4_SUCCESS_COUNT_MINUTES, Constants.IPV4_SUCCESS_LOCK_MINUTES);
}
private final static String getErrorIpKey(String ipv4){
return Constants.REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4 + ipv4;
}
private final static String getSuccessIpKey(String ipv4){
return Constants.REDIS_PASSWORD_SUCCESS_COUNT_FOR_IPV4 + ipv4;
}
private final static String getLockIpv4Key(String ipv4){
return Constants.IPV4_LOCK + ipv4;
}
private boolean validatePassword(String paramPass, String targetPassword) {
return StringUtils.defaultString(targetPassword, "").equals(PasswordUtil.MD5(paramPass.toLowerCase() + pwdSalt));
}
......
package cn.quantgroup.xyqb.service.user;
/**
* IPV4锁机制Service
* @author renwc
*/
public interface ILockIpv4Service {
/**
* 向该phoneNo添加错误计数器
* @param phoneNo
*/
void countErrorByPhoneNo(String phoneNo);
/**
* 向该ipv4添加错误计数器
* @param ip - 目标ip
*/
void countErrorByIpv4(String ip);
/**
* 锁定IPV4
* @param ip - 目标ip
* @param count - 错误计数
*/
void lockErrorIpv4(String ip, long count);
/**
* 向该phoneNo添加错误计数器
* @param ip - 目标ip
*/
void countSuccessByIpv4(String ip);
/**
* 锁定IPV4
* @param ip - 目标ip
* @param count - 错误计数
*/
void lockSuccessIpv4(String ip, long count);
}
package cn.quantgroup.xyqb.service.user.impl;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.exception.PasswordErrorLimitException;
import cn.quantgroup.xyqb.service.user.ILockIpv4Service;
import cn.quantgroup.xyqb.util.DateUtils;
import cn.quantgroup.xyqb.util.ValidationUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* IPV4锁机制Service实现
* @author renwc
*/
@Service
public class LockIpv4ServiceImpl implements ILockIpv4Service {
private static final Logger LOGGER = LoggerFactory.getLogger(ILockIpv4Service.class);
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> stringRedisTemplate;
@Override
public void countErrorByPhoneNo(String phoneNo) {
// 密码错误时,给该账号添加计数器
String key = Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
if (!stringRedisTemplate.hasKey(key)) {
LOGGER.info("添加错误计数器,key={}", key);
stringRedisTemplate.opsForValue().set(key, String.valueOf(0), DateUtils.getSeconds(), TimeUnit.SECONDS);
}
// 密码错误计数
Long errorCount = stringRedisTemplate.opsForValue().increment(key, 1L);
if (errorCount > Constants.Image_Need_Count) {
LOGGER.info("用户名或密码不正确,phoneNo={}", phoneNo);
throw new PasswordErrorLimitException("用户名或密码不正确");
} else if (Objects.equals(errorCount, Constants.Image_Need_Count)) {
LOGGER.info("请输入图形验证码,phoneNo={}", phoneNo);
throw new PasswordErrorLimitException("请输入图形验证码");
}
}
@Override
public void countErrorByIpv4(String ipv4) {
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){
return;
}*/
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getErrorIpKey(ipv4);
if(!stringRedisTemplate.hasKey(ipv4Key)){
// 计数周期1分钟
stringRedisTemplate.opsForValue().set(ipv4Key, String.valueOf(0), Constants.IPV4_FAILED_COUNT_MINUTES, TimeUnit.MINUTES);
}
Long count = stringRedisTemplate.opsForValue().increment(ipv4Key, 1L);
LOGGER.info("Lock_ipv4: count error ip access: ip={}, count={}", ipv4, count);
lockErrorIpv4(ipv4, count);
}
}
@Override
public void lockErrorIpv4(String ip, long count){
// 每分钟计数阈值
long counts = Constants.IPV4_LOCK_ON_FAILED_COUNTS;
String redisCounts = stringRedisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisCounts) && Integer.valueOf(redisCounts) > 0){
counts = Integer.valueOf(redisCounts);
}
if(count < counts){
return;
}
// 锁定时长
long minutes = Constants.IPV4_FAILED_LOCK_MINUTES;
String redisMinutes = stringRedisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisMinutes) && Integer.valueOf(redisMinutes) > 0){
minutes = Integer.valueOf(redisMinutes);
}
String lockIpv4Key = getLockIpv4Key(ip);
stringRedisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), minutes, TimeUnit.MINUTES);
LOGGER.info("Lock_ipv4: locked error ip access:{}, error overstep {} times in {} minutes, do lock {} minutes", ip, counts, Constants.IPV4_FAILED_COUNT_MINUTES, minutes);
}
@Override
public void countSuccessByIpv4(String ipv4) {
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){
return;
}*/
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getSuccessIpKey(ipv4);
if(!stringRedisTemplate.hasKey(ipv4Key)){
// 计数周期1分钟
stringRedisTemplate.opsForValue().set(ipv4Key, String.valueOf(0), Constants.IPV4_SUCCESS_COUNT_MINUTES, TimeUnit.MINUTES);
}
Long count = stringRedisTemplate.opsForValue().increment(ipv4Key, 1L);
LOGGER.info("Lock_ipv4: count success ip access: ip={}, count={}", ipv4, count);
lockSuccessIpv4(ipv4, count);
}
}
@Override
public void lockSuccessIpv4(String ip, long count){
// 每小时计数阈值
if(count < Constants.IPV4_LOCK_ON_SUCCESS_COUNTS){
return;
}
// 锁定时长
String lockIpv4Key = getLockIpv4Key(ip);
stringRedisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), Constants.IPV4_SUCCESS_LOCK_MINUTES, TimeUnit.MINUTES);
LOGGER.info("Lock_ipv4: locked success ip access:{}, success overstep {} times in {} minutes, do lock {} minutes", ip, Constants.IPV4_LOCK_ON_SUCCESS_COUNTS, Constants.IPV4_SUCCESS_COUNT_MINUTES, Constants.IPV4_SUCCESS_LOCK_MINUTES);
}
private final static String getErrorIpKey(String ipv4){
return Constants.REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4 + ipv4;
}
private final static String getSuccessIpKey(String ipv4){
return Constants.REDIS_PASSWORD_SUCCESS_COUNT_FOR_IPV4 + ipv4;
}
private final static String getLockIpv4Key(String ipv4){
return Constants.IPV4_LOCK + ipv4;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment