登录增加验证码切换

This commit is contained in:
2026-04-06 22:58:55 +08:00
parent b0751cf45e
commit dd1bda704f
4 changed files with 111 additions and 8 deletions

View File

@@ -20,7 +20,7 @@ public class AuthController {
private UserService userService;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody Map<String, String> request, HttpSession session) {
public ResponseEntity<?> login(@RequestBody Map<String, String> request, HttpSession session, jakarta.servlet.http.HttpServletRequest httpRequest) {
String username = request.get("username");
String password = request.get("password");
String captcha = request.get("captcha");
@@ -31,7 +31,9 @@ public class AuthController {
}
try {
String token = userService.login(username, password);
// 获取客户端 IP
String clientIp = getClientIp(httpRequest);
String token = userService.login(username, password, clientIp);
User user = userService.findByUsername(username);
// 直接读取存储空间,不重算
@@ -64,7 +66,7 @@ public class AuthController {
}
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody Map<String, String> request) {
public ResponseEntity<?> register(@RequestBody Map<String, String> request, jakarta.servlet.http.HttpServletRequest httpRequest) {
String username = request.get("username");
String password = request.get("password");
String nickname = request.get("nickname");
@@ -73,7 +75,9 @@ public class AuthController {
return ResponseEntity.badRequest().body(Map.of("message", "用户名已存在"));
}
User user = userService.createUser(username, password, nickname != null ? nickname : username);
// 获取客户端 IP
String clientIp = getClientIp(httpRequest);
User user = userService.createUser(username, password, nickname != null ? nickname : username, clientIp);
return ResponseEntity.ok(Map.of("message", "注册成功", "data", Map.of("id", user.getId())));
}
@@ -115,4 +119,22 @@ public class AuthController {
return ResponseEntity.ok(body);
}
/**
* 获取客户端真实 IP支持代理
*/
private String getClientIp(jakarta.servlet.http.HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 多级代理时取第一个
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
}

View File

@@ -30,4 +30,10 @@ public class User extends BaseEntity {
@TableField("storage_limit")
private Long storageLimit;
@TableField("register_ip")
private String registerIp;
@TableField("allowed_ips")
private String allowedIps; // 允许的IP段逗号分隔如 "192.168.1.0/24,10.0.0.0/8"
}

View File

@@ -41,7 +41,7 @@ public class UserService {
return userMapper.selectById(id);
}
public String login(String username, String password) {
public String login(String username, String password, String clientIp) {
User user = findByUsername(username);
if (user == null) {
throw new RuntimeException("用户不存在");
@@ -49,14 +49,86 @@ public class UserService {
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new RuntimeException("密码错误");
}
// 校验 IP检查客户端 IP 是否在允许范围内
String allowedIps = user.getAllowedIps();
if (allowedIps != null && !allowedIps.isEmpty()) {
if (!isIpAllowed(clientIp, allowedIps)) {
throw new RuntimeException("登录IP不在允许范围内");
}
}
return jwtUtil.generateToken(username, user.getId());
}
/**
* 检查客户端IP是否在允许的IP段列表中
*/
private boolean isIpAllowed(String clientIp, String allowedIps) {
if (clientIp == null || clientIp.isEmpty()) {
return false;
}
String[] ips = allowedIps.split(",");
for (String ip : ips) {
ip = ip.trim();
if (ip.isEmpty()) continue;
// 精确匹配
if (clientIp.equals(ip)) {
return true;
}
// 网段匹配(如 192.168.1.0/24
if (ip.contains("/")) {
if (cidrContains(ip, clientIp)) {
return true;
}
}
}
return false;
}
/**
* 判断 CIDR 网段是否包含指定 IP
*/
private boolean cidrContains(String cidr, String ip) {
try {
String[] parts = cidr.split("/");
String baseIp = parts[0];
int prefix = Integer.parseInt(parts[1]);
byte[] ipBytes = ipToBytes(ip);
byte[] baseBytes = ipToBytes(baseIp);
int mask = 0xFFFFFFFF << (32 - prefix);
int ipInt = bytesToInt(ipBytes);
int baseInt = bytesToInt(baseBytes);
return (ipInt & mask) == (baseInt & mask);
} catch (Exception e) {
return false;
}
}
private byte[] ipToBytes(String ip) {
String[] parts = ip.split("\\.");
byte[] bytes = new byte[4];
for (int i = 0; i < 4; i++) {
bytes[i] = (byte) Integer.parseInt(parts[i]);
}
return bytes;
}
private int bytesToInt(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
}
public void logout(Long userId) {
jwtUtil.invalidateToken(userId);
}
public User createUser(String username, String password, String nickname) {
public User createUser(String username, String password, String nickname, String registerIp) {
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
@@ -64,6 +136,7 @@ public class UserService {
user.setStatus(1);
user.setStorageUsed(0L);
user.setStorageLimit((long) storageLimitGb * 1024 * 1024 * 1024);
user.setRegisterIp(registerIp);
userMapper.insert(user);
return user;
}

View File

@@ -16,6 +16,8 @@ CREATE TABLE IF NOT EXISTS sys_user (
status INT DEFAULT 1 COMMENT '状态 0-禁用 1-启用',
storage_used BIGINT DEFAULT 0 COMMENT '已用存储空间(字节)',
storage_limit BIGINT DEFAULT 10737418240 COMMENT '存储限制(字节) 默认10GB',
register_ip VARCHAR(50) COMMENT '注册IP',
allowed_ips VARCHAR(500) COMMENT '允许的IP段逗号分隔',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
is_deleted INT DEFAULT 0 COMMENT '是否删除 0-否 1-是'
@@ -73,6 +75,6 @@ CREATE TABLE IF NOT EXISTS sys_message (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息表';
-- 插入默认管理员账户 (密码: admin123)
INSERT INTO sys_user (username, password, nickname, status, storage_limit)
VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '管理员', 1, 10737418240)
INSERT INTO sys_user (username, password, nickname, status, storage_limit, allowed_ips)
VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '管理员', 1, 10737418240, '0.0.0.0/0')
ON DUPLICATE KEY UPDATE username = username;