登录增加验证码切换
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user