nnnn
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
CREATE TABLE `cai_ip_record`
|
||||
(
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '子账户ID',
|
||||
`count_date` date NOT NULL COMMENT '统计日期',
|
||||
`ip_addr` varchar(100) NOT NULL COMMENT 'IP地址',
|
||||
`path_addr` varchar(255) NULL COMMENT '请求地址',
|
||||
`business_id` varchar(255) NULL,
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.ruoyi.cai.kit.VerificationCodeCheck;
|
||||
import com.ruoyi.cai.manager.CurrentUserManager;
|
||||
import com.ruoyi.cai.manager.LoginAfterManager;
|
||||
import com.ruoyi.cai.manager.SystemConfigManager;
|
||||
import com.ruoyi.cai.service.IpBlackService;
|
||||
import com.ruoyi.cai.service.IpRecordService;
|
||||
import com.ruoyi.cai.service.SmsVerifyService;
|
||||
import com.ruoyi.cai.service.UserService;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
@@ -142,15 +144,24 @@ public class AuthAppController {
|
||||
|
||||
@Autowired
|
||||
private LoginAfterManager loginAfterManager;
|
||||
@Autowired
|
||||
private IpRecordService ipRecordService;
|
||||
@Autowired
|
||||
private IpBlackService ipBlackService;
|
||||
|
||||
@PostMapping("/login")
|
||||
@Operation(summary = "登陆")
|
||||
@Log(title = "登陆", businessType = BusinessType.OTHER, isSaveDb = false)
|
||||
public R<LoginVo> login(@Validated @RequestBody LoginCaiUser loginBody){
|
||||
LoginVo vo = new LoginVo();
|
||||
String token = caiLoginManager.login(loginBody.getUsername(), loginBody.getPassword());
|
||||
vo.setToken(token);
|
||||
vo.setUserInfo(currentUserManager.currentInfo());
|
||||
try {
|
||||
String token = caiLoginManager.login(loginBody.getUsername(), loginBody.getPassword());
|
||||
vo.setToken(token);
|
||||
vo.setUserInfo(currentUserManager.currentInfo());
|
||||
}catch (Exception e){
|
||||
ipRecordService.saveLoginIp(ServletUtils.getClientIP());
|
||||
throw e;
|
||||
}
|
||||
// 异步调用通知
|
||||
// loginAfterManager.loginAfter(LoginHelper.getUserId());
|
||||
return R.ok(vo);
|
||||
|
||||
@@ -93,15 +93,24 @@ public class CaiLoginManager {
|
||||
private IgnoreDataService ignoreDataService;
|
||||
@Autowired
|
||||
private AmqpHttpProducer amqpHttpProducer;
|
||||
@Autowired
|
||||
private IpRecordService ipRecordService;
|
||||
@Autowired
|
||||
private IpBlackService ipBlackService;
|
||||
|
||||
public String login(String username,String password){
|
||||
String clientIP = ServletUtils.getClientIP();
|
||||
Boolean b = ipBlackService.checkIp(clientIP);
|
||||
if(b){
|
||||
log.error("登录拦截了异常IP={}", clientIP);
|
||||
throw new ServiceException("40305");
|
||||
}
|
||||
User user = userService.getByUsername(username);
|
||||
if(user == null){
|
||||
|
||||
throw new ServiceException("用户不存在或密码错误");
|
||||
}
|
||||
String imei = ServletUtils.getImei();
|
||||
UserForbidManager.CheckForbid forbid = userForbidManager.checkForbid(user.getId(), user.getUsercode(), imei, ServletUtils.getClientIP());
|
||||
UserForbidManager.CheckForbid forbid = userForbidManager.checkForbid(user.getId(), user.getUsercode(), imei, clientIP);
|
||||
if(forbid != null && forbid.isForbid()){
|
||||
throw new ServiceException(forbid.getMessage());
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ public class IpBlackController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody IpBlack bo) {
|
||||
return toAjax(ipBlackService.save(bo));
|
||||
bo.setEnableStatus(1);
|
||||
ipBlackService.saveIp(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.ruoyi.cai.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.cai.domain.IpRecord;
|
||||
import com.ruoyi.cai.dto.admin.vo.IpRecordAdminVO;
|
||||
import com.ruoyi.cai.service.IpRecordService;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
||||
@@ -41,8 +43,8 @@ public class IpRecordController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("cai:ipRecord:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<IpRecord> list(IpRecord bo, PageQuery pageQuery) {
|
||||
Page<IpRecord> page = ipRecordService.page(pageQuery.build(), Wrappers.lambdaQuery(bo));
|
||||
public TableDataInfo<IpRecordAdminVO> list(IpRecordAdminVO bo, PageQuery pageQuery) {
|
||||
IPage<IpRecordAdminVO> page = ipRecordService.pageAdmin(bo,pageQuery);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class IpBlack implements Serializable {
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private Long enableStatus;
|
||||
private Integer enableStatus;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,7 @@ public class IpRecord implements Serializable{
|
||||
*/
|
||||
@TableId(value = "id",type = IdType.AUTO)
|
||||
private String id;
|
||||
private LocalDate countDate;
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ruoyi.cai.dto.admin.vo;
|
||||
|
||||
import com.ruoyi.cai.domain.IpRecord;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class IpRecordAdminVO extends IpRecord {
|
||||
private boolean black;
|
||||
private Integer minNumber;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import lombok.Data;
|
||||
public class MinUser {
|
||||
private Long id;
|
||||
private Integer gender;
|
||||
private String mobile;
|
||||
/**
|
||||
* 隐身模式 0-关闭 1-打开
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.ruoyi.cai.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.cai.domain.IpRecord;
|
||||
import com.ruoyi.cai.dto.admin.vo.IpRecordAdminVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* ip访问记录Mapper接口
|
||||
@@ -11,4 +15,5 @@ import com.ruoyi.cai.domain.IpRecord;
|
||||
*/
|
||||
public interface IpRecordMapper extends BaseMapper<IpRecord> {
|
||||
|
||||
IPage<IpRecordAdminVO> pageAdmin(Page<Object> build, @Param("bo") IpRecordAdminVO bo);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,7 @@ import com.ruoyi.cai.domain.IpBlack;
|
||||
*/
|
||||
public interface IpBlackService extends IService<IpBlack> {
|
||||
|
||||
Boolean checkIp(String clientIP);
|
||||
|
||||
void saveIp(IpBlack ipBlack);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.ruoyi.cai.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.ruoyi.cai.domain.IpRecord;
|
||||
import com.ruoyi.cai.dto.admin.vo.IpRecordAdminVO;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
|
||||
/**
|
||||
* ip访问记录Service接口
|
||||
@@ -10,4 +13,7 @@ import com.ruoyi.cai.domain.IpRecord;
|
||||
* @date 2025-12-05
|
||||
*/
|
||||
public interface IpRecordService extends IService<IpRecord> {
|
||||
IPage<IpRecordAdminVO> pageAdmin(IpRecordAdminVO bo, PageQuery pageQuery);
|
||||
|
||||
void saveLoginIp(String clientIP);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.ruoyi.cai.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ruoyi.cai.domain.IpBlack;
|
||||
import com.ruoyi.cai.mapper.IpBlackMapper;
|
||||
import com.ruoyi.cai.service.IpBlackService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -17,4 +19,20 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class IpBlackServiceImpl extends ServiceImpl<IpBlackMapper,IpBlack> implements IpBlackService {
|
||||
|
||||
@Override
|
||||
public Boolean checkIp(String clientIP) {
|
||||
boolean exists = this.exists(Wrappers.lambdaQuery(IpBlack.class).eq(IpBlack::getIpAddr, clientIP)
|
||||
.eq(IpBlack::getEnableStatus, 1));
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveIp(IpBlack ipBlack){
|
||||
boolean exists = this.exists(Wrappers.lambdaQuery(IpBlack.class).eq(IpBlack::getIpAddr, ipBlack.getIpAddr()));
|
||||
if(exists){
|
||||
throw new ServiceException("IP已经存在");
|
||||
}
|
||||
this.save(ipBlack);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
package com.ruoyi.cai.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ruoyi.cai.domain.IpRecord;
|
||||
import com.ruoyi.cai.dto.admin.vo.IpRecordAdminVO;
|
||||
import com.ruoyi.cai.mapper.IpRecordMapper;
|
||||
import com.ruoyi.cai.service.IpRecordService;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.redisson.api.RAtomicLong;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* ip访问记录Service业务层处理
|
||||
*
|
||||
@@ -17,4 +30,109 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class IpRecordServiceImpl extends ServiceImpl<IpRecordMapper,IpRecord> implements IpRecordService {
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
|
||||
@Override
|
||||
public IPage<IpRecordAdminVO> pageAdmin(IpRecordAdminVO bo, PageQuery pageQuery){
|
||||
IPage<IpRecordAdminVO> page = baseMapper.pageAdmin(pageQuery.build(), bo);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLoginIp(String ip) {
|
||||
long l = saveIp(ip);
|
||||
if(l < 5){
|
||||
return;
|
||||
}
|
||||
if(l % 5 == 0){
|
||||
try {
|
||||
this.saveIpDb(ip);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("保存IP失败",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void saveIpDb(String ip) throws InterruptedException {
|
||||
IpRecord ipRecord = getByIpAndDate(ip, null);
|
||||
if(ipRecord == null){
|
||||
String lockKey = getLockKey(ip);
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
boolean b = lock.tryLock(5, TimeUnit.SECONDS);
|
||||
if(b){
|
||||
ipRecord = getByIpAndDate(ip, null);
|
||||
if(ipRecord == null){
|
||||
IpRecord record = new IpRecord();
|
||||
record.setIpAddr(ip);
|
||||
long numb = getIp(ip);
|
||||
record.setPathAddr("/api/auth/login");
|
||||
record.setCountDate(LocalDate.now());
|
||||
record.setNumber(numb);
|
||||
record.setUpdateTime(LocalDateTime.now());
|
||||
this.save(record);
|
||||
}else{
|
||||
long numb = getIp(ip);
|
||||
IpRecord record = new IpRecord();
|
||||
record.setId(ipRecord.getId());
|
||||
record.setNumber(numb);
|
||||
record.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(record);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}else{
|
||||
long numb = getIp(ip);
|
||||
IpRecord record = new IpRecord();
|
||||
record.setId(ipRecord.getId());
|
||||
record.setNumber(numb);
|
||||
record.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(record);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String KEY_LOCK = "cai:ipRecordLock:%s";
|
||||
|
||||
public static String getLockKey(String ip){
|
||||
return String.format(KEY_LOCK, ip);
|
||||
}
|
||||
|
||||
private IpRecord getByIpAndDate(String ip,LocalDate date){
|
||||
if(date == null){
|
||||
date = LocalDate.now();
|
||||
}
|
||||
return this.getOne(Wrappers.lambdaQuery(IpRecord.class).eq(IpRecord::getIpAddr, ip).eq(IpRecord::getCountDate, date).last("limit 1"));
|
||||
}
|
||||
|
||||
public static String KEY = "cai:ipRecord:%s:%s";
|
||||
|
||||
private String getNow(){
|
||||
return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
}
|
||||
|
||||
private String getKey(String ip){
|
||||
return String.format(KEY, ip, getNow());
|
||||
}
|
||||
|
||||
public long getIp(String ip){
|
||||
String key = getKey(ip);
|
||||
RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
|
||||
return atomicLong.get();
|
||||
}
|
||||
|
||||
public long saveIp(String ip){
|
||||
String key = getKey(ip);
|
||||
RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
|
||||
long l = atomicLong.incrementAndGet();
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.ruoyi.cai.service.impl;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.api.client.util.SecurityUtils;
|
||||
import com.ruoyi.cai.domain.SmsVerify;
|
||||
import com.ruoyi.cai.domain.User;
|
||||
import com.ruoyi.cai.domain.UserInfo;
|
||||
import com.ruoyi.cai.dto.commom.user.MinUser;
|
||||
import com.ruoyi.cai.enums.CodeEnum;
|
||||
import com.ruoyi.cai.enums.SystemConfigEnum;
|
||||
import com.ruoyi.cai.kit.AliSmsKit;
|
||||
@@ -17,6 +19,7 @@ import com.ruoyi.cai.service.SmsVerifyService;
|
||||
import com.ruoyi.cai.service.UserInfoService;
|
||||
import com.ruoyi.cai.service.UserService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.helper.LoginHelper;
|
||||
import com.ruoyi.common.utils.ServletUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -81,12 +84,24 @@ public class SmsVerifyServiceImpl extends ServiceImpl<SmsVerifyMapper,SmsVerify>
|
||||
throw new ServiceException("手机号已经被注册使用!");
|
||||
}
|
||||
}else if(codeEnum == CodeEnum.RESET_PASSWORD){
|
||||
Long userId = LoginHelper.getUserId();
|
||||
MinUser miniUser = userService.getMinUserById(userId);
|
||||
if(miniUser == null || !mobile.equalsIgnoreCase(miniUser.getMobile())){
|
||||
log.error("手机号与登录手机号不一致");
|
||||
throw new ServiceException("手机号未注册!");
|
||||
}
|
||||
long count = userService.count(Wrappers.lambdaQuery(User.class)
|
||||
.eq(User::getMobile, mobile));
|
||||
if(count == 0){
|
||||
throw new ServiceException("手机号未注册!");
|
||||
}
|
||||
}else if(codeEnum == CodeEnum.RESET_ADOLESCENT){
|
||||
Long userId = LoginHelper.getUserId();
|
||||
MinUser miniUser = userService.getMinUserById(userId);
|
||||
if(miniUser == null || !mobile.equalsIgnoreCase(miniUser.getMobile())){
|
||||
log.error("手机号与登录手机号不一致");
|
||||
throw new ServiceException("手机号未注册!");
|
||||
}
|
||||
long count = userService.count(Wrappers.lambdaQuery(User.class)
|
||||
.eq(User::getMobile, mobile));
|
||||
if(count == 0){
|
||||
|
||||
@@ -15,5 +15,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
<select id="pageAdmin" resultType="com.ruoyi.cai.dto.admin.vo.IpRecordAdminVO">
|
||||
select t1.*,if(t2.id,1,0) as black
|
||||
from cai_ip_record t1
|
||||
left join cai_ip_black t2 on t1.ip_addr = t2.ip_addr and t2.enable_status = 1
|
||||
where 1=1
|
||||
<if test="bo.ipAddr != null and bo.ipAddr != ''">
|
||||
and t1.ip_addr = #{bo.ipAddr}
|
||||
</if>
|
||||
<if test="bo.minNumber != null">
|
||||
and t1.number > #{bo.minNumber}
|
||||
</if>
|
||||
order by t1.count_date desc, ip_addr
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -100,7 +100,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
limit 20
|
||||
</select>
|
||||
<select id="getMinUserById" resultType="com.ruoyi.cai.dto.commom.user.MinUser">
|
||||
select id,gender
|
||||
select id,gender,mobile
|
||||
from cai_user t1
|
||||
where id = #{userId}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user