Commit 52c0ae50 authored by 董建华's avatar 董建华

新增登陆失败字段

parent dcb47dd5
......@@ -5,6 +5,7 @@ import cn.quantgroup.xyqb.entity.LoginInfo;
import cn.quantgroup.xyqb.entity.enums.Device;
import cn.quantgroup.xyqb.entity.enums.KeyType;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.LoginRefuseResult;
import cn.quantgroup.xyqb.repository.LoginInfoRepository;
import cn.quantgroup.xyqb.repository.WhiteListRepository;
import com.google.common.collect.Maps;
......@@ -21,10 +22,9 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author :dongjianhua
......@@ -95,20 +95,24 @@ public class DeviceInterceptorAspect {
deviceId = DEFAULT_CODE;
}
if (!verification(scDeviceId, phone)) {
LoginRefuseResult result = verification(scDeviceId, phone);
if (!result.isPass()) {
log.warn("登录命中风控策略deviceId:{},phone:{},realIp:{},deviceCode:{}", deviceId, phone, realIp, deviceCode);
return JsonResult.buildErrorStateResult(ALERT_WORDS, null);
}
/**
* 保存登录信息
*/
saveLoginInfo(phone, deviceCode, deviceId, realIp);
Object loginResult = null;
try {
return pjp.proceed();
loginResult = pjp.proceed();
} catch (Exception e) {
throw e;
} finally {
/**
* 保存登录信息
*/
saveLoginInfo(phone, deviceCode, deviceId, realIp, result, loginResult);
}
return loginResult;
}
/**
......@@ -116,20 +120,22 @@ public class DeviceInterceptorAspect {
* @param phone
* @return
*/
private boolean verification(String deviceId, String phone) {
private LoginRefuseResult verification(String deviceId, String phone) {
try {
/**
* 默认code不需要
*/
if (DEFAULT_CODE.equals(deviceId)) {
return true;
return LoginRefuseResult.builder()
.isPass(Boolean.TRUE).build();
}
/**
* 如果没传手机也放过吧
*/
if (null == phone || "".equals(phone)) {
log.warn("怎么没传手机号进来啊暂时放过吧");
return true;
return LoginRefuseResult.builder()
.isPass(Boolean.TRUE).build();
}
Long deviceNum = loginInfoRepository.countByDeviceId(deviceId);
......@@ -137,33 +143,55 @@ public class DeviceInterceptorAspect {
if (DEVICE_REFUSE_COUNT.compareTo(deviceNum) < 0) {
if (!isWhite(deviceId, KeyType.DEVICEID)) {
log.warn("此设备登录命中拒绝策略,并且未在白名单deviceId:{}超过{}个拒绝登录", deviceId, deviceNum);
return true;
return LoginRefuseResult.builder()
.isPass(Boolean.TRUE).build();
}
log.warn("此设备登录命中拒绝策略存在白名单deviceId:{}", deviceId);
return false;
return LoginRefuseResult.builder()
.isPass(Boolean.FALSE)
.rule(1)
.threshold(DEVICE_REFUSE_COUNT.intValue())
.value(deviceNum.intValue())
.build();
}
List<CountDevice> countDevices = loginInfoRepository.countByPhoneAndDevice(phone);
if (CollectionUtils.isEmpty(countDevices)) {
return true;
return LoginRefuseResult.builder()
.isPass(Boolean.TRUE)
.build();
}
/**
* 总数
*/
long sum = countDevices.stream().mapToLong(CountDevice::getNum).sum();
Set<Map.Entry<Device, Long>> entries = DEVICE_REFUSE_STRATEGY.entrySet();
for (Map.Entry<Device, Long> entry : entries) {
for (CountDevice countDevice : countDevices) {
Long aLong = DEVICE_REFUSE_STRATEGY.get(countDevice.getDevice());
if (null != aLong && countDevice.getNum().compareTo(aLong) > 0) {
Long threshold = entry.getValue();
if (threshold.compareTo(sum) < 0) {
if (!isWhite(deviceId, KeyType.PHONE)) {
log.warn("此账户登录命中拒绝策略并且没有白名单phone:{},device", phone);
return false;
return LoginRefuseResult.builder()
.isPass(Boolean.FALSE)
.rule(2)
.threshold(threshold.intValue())
.value(Long.valueOf(sum).intValue())
.build();
}
log.warn("此账户登录命中拒绝策略存在白名单phone:{}", phone);
}
}
return true;
} catch (Exception e) {
log.error("用户登录策略校验异常了", e);
}
return true;
return LoginRefuseResult.builder()
.isPass(Boolean.TRUE)
.build();
}
/**
......@@ -174,7 +202,7 @@ public class DeviceInterceptorAspect {
* @param deviceId
* @param ip
*/
private void saveLoginInfo(String phone, String deviceCode, String deviceId, String ip) {
private void saveLoginInfo(String phone, String deviceCode, String deviceId, String ip, LoginRefuseResult refuseResult, Object loginResult) {
try {
/**
* 默认code不需要
......@@ -186,30 +214,37 @@ public class DeviceInterceptorAspect {
Device device = Device.valueOfCode(deviceCode);
if (null == device) {
log.warn("咋回事啊没找到code对应的设备code:{}", deviceCode);
}
Long count = 1L;
LoginInfo info = loginInfoRepository.getFirstByPhoneNoAndDevice(phone, device);
if (null == info) {
info = new LoginInfo();
} else {
count = info.getLoginCount() + 1L;
}
LoginInfo info = new LoginInfo();
info.setPhoneNo(phone);
info.setDeviceId(deviceId);
info.setLastLoginAt(Timestamp.valueOf(LocalDateTime.now()));//当前时间
info.setDevice(device);
info.setLoginCount(count);
info.setIp(ip);
info.setLastIp(ip);
info.setIsPass(Boolean.TRUE);
if (!refuseResult.isPass()) {
info.setIsPass(Boolean.FALSE);
info.setHitRule(refuseResult.getRule());
info.setThreshold(refuseResult.getThreshold());
info.setValue(refuseResult.getValue());
}
if (null == loginResult) {
info.setIsLogin(Boolean.FALSE);
} else {
if (loginResult instanceof JsonResult) {
if (((JsonResult) loginResult).isSuccess()) {
info.setIsLogin(Boolean.TRUE);
} else {
info.setIsLogin(Boolean.FALSE);
info.setLoginFailMsg(((JsonResult) loginResult)
.getMsg());
}
}
}
loginInfoRepository.save(info);
} catch (Exception e) {
log.error("保存登录信息异常phone:{}", phone, e);
......
......@@ -27,7 +27,7 @@ package cn.quantgroup.xyqb.entity;
{
@NamedNativeQuery(
name = "LoginInfo.countByPhoneAndDevice",
query = "select count(1) num ,device from login_info where phone_no=?1 and last_login_at> DATE_ADD(CURRENT_TIMESTAMP(),INTERVAL -90 DAY group by device",
query = "select count(DISTINCT device_id) num ,device from login_info where phone_no=?1 and created_at > DATE_ADD(CURRENT_TIMESTAMP(),INTERVAL -90 DAY) group by device",
resultClass = CountDevice.class
)
}
......
......@@ -30,14 +30,26 @@ public class LoginInfo extends BaseEntity {
@Column(name = "device")
private Device device;
@Column(name = "last_ip")
private String lastIp;
@Column(name = "ip")
private String ip;
@Column(name = "login_count")
private Long loginCount;
@Column(name = "is_login")
private Boolean isLogin;
@Column(name = "last_login_at")
private Timestamp lastLoginAt;
@Column(name = "login_fail_msg")
private String loginFailMsg;
@Column(name = "is_pass")
private Boolean isPass;
@Column(name = "hit_rule")
private int hitRule;
@Column(name = "threshold")
private int threshold;
@Column(name = "value")
private int value;
/**
......@@ -46,16 +58,19 @@ public class LoginInfo extends BaseEntity {
* `phone_no` varchar(15) NOT NULL COMMENT '手机号',
* `device_id` varchar(50) NOT NULL COMMENT '设备ID',
* `device` int(2) DEFAULT NULL COMMENT '设备类型(0安卓,1IOS)',
* `last_ip` varchar(30) DEFAULT NULL COMMENT '同手机设备最后一次登录的IP',
* `login_count` int(11) DEFAULT '1' COMMENT '同账户设备登录次数',
* `last_login_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次登陆时间',
* `ip` varchar(30) DEFAULT NULL COMMENT '登录的IP',
* `is_login` int(1) DEFAULT '1' COMMENT '是否登录成功',
* `is_pass` int(1) DEFAULT '1' COMMENT '是否通过风控策略',
* `hit_rule` int(1) DEFAULT '0' COMMENT '命中的规则',
* `threshold` int(3) DEFAULT NULL COMMENT '阈值',
* `value` int(10) DEFAULT '0' COMMENT '实际的值',
* `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(第一次登陆时间)',
* `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
* PRIMARY KEY (`id`),
* UNIQUE KEY `phone_deviceid_idx` (`phone_no`,`device_id`) USING BTREE,
* KEY `deviceid_idx` (`device_id`) USING BTREE,
* KEY `create_at_idx` (`created_at`) USING BTREE,
* KEY `last_login_at_idx` (`last_login_at`) USING BTREE
* KEY `updated_at_idx` (`updated_at`) USING BTREE,
* KEY `phone_idx` (`phone_no`) USING BTREE
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='登录信息表';
*/
}
......@@ -7,7 +7,9 @@ public enum Device {
ANDROID("安卓", "android"),
IOS("IOS", "ios");
IOS("IOS", "ios"),
OTHER("other","other"),
;
private String desc;
private String code;
......@@ -19,7 +21,7 @@ public enum Device {
public static Device valueOfCode(String code) {
if(null == code){
return null;
return Device.OTHER;
}
for (Device device : Device.values()) {
if (device.code.equals(code)) {
......
package cn.quantgroup.xyqb.model;
import lombok.Builder;
import lombok.Data;
/**
* @author :dongjianhua
* @date :Created in 2020/11/23 15:07
* @description:拒绝结果
* @modified By:
* @version:
*/
@Data
@Builder
public class LoginRefuseResult {
private int rule;
private int threshold;
private int value;
private boolean isLogin;
private boolean isPass;
}
......@@ -16,7 +16,7 @@ public interface LoginInfoRepository extends JpaRepository<LoginInfo, Long> {
* @param deviceId 设备维度策略
* @return
*/
@Query(value = "select count(1) from login_info where device_id=?1 and last_login_at> DATE_ADD(CURRENT_TIMESTAMP(),INTERVAL -90 DAY)", nativeQuery = true)
@Query(value = "select count(distinct device_id) from login_info where device_id=?1 and created_at> DATE_ADD(CURRENT_TIMESTAMP(),INTERVAL -90 DAY)", nativeQuery = true)
Long countByDeviceId(String deviceId);
......
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