From dd1bda704f7cc0cbc2d8aaff263ca673f159b374 Mon Sep 17 00:00:00 2001 From: gaoxq <376340421@qq.com> Date: Mon, 6 Apr 2026 22:58:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=A2=9E=E5=8A=A0=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filesystem/controller/AuthController.java | 30 +++++++- src/main/java/com/filesystem/entity/User.java | 6 ++ .../com/filesystem/service/UserService.java | 77 ++++++++++++++++++- src/main/resources/db/init.sql | 6 +- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/filesystem/controller/AuthController.java b/src/main/java/com/filesystem/controller/AuthController.java index b95434c..dfb158e 100644 --- a/src/main/java/com/filesystem/controller/AuthController.java +++ b/src/main/java/com/filesystem/controller/AuthController.java @@ -20,7 +20,7 @@ public class AuthController { private UserService userService; @PostMapping("/login") - public ResponseEntity login(@RequestBody Map request, HttpSession session) { + public ResponseEntity login(@RequestBody Map 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 request) { + public ResponseEntity register(@RequestBody Map 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; + } } diff --git a/src/main/java/com/filesystem/entity/User.java b/src/main/java/com/filesystem/entity/User.java index af138c4..aa3cfef 100644 --- a/src/main/java/com/filesystem/entity/User.java +++ b/src/main/java/com/filesystem/entity/User.java @@ -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" } diff --git a/src/main/java/com/filesystem/service/UserService.java b/src/main/java/com/filesystem/service/UserService.java index 79f5a93..1b7659e 100644 --- a/src/main/java/com/filesystem/service/UserService.java +++ b/src/main/java/com/filesystem/service/UserService.java @@ -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; } diff --git a/src/main/resources/db/init.sql b/src/main/resources/db/init.sql index 96e2380..89bcfe6 100644 --- a/src/main/resources/db/init.sql +++ b/src/main/resources/db/init.sql @@ -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;