mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-09-13 14:57:16 +08:00
refactor: 优化密码策略处理
This commit is contained in:
@@ -23,6 +23,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -68,7 +69,7 @@ public class AuthController {
|
||||
@SaIgnore
|
||||
@Operation(summary = "账号登录", description = "根据账号和密码进行登录认证")
|
||||
@PostMapping("/account")
|
||||
public R<LoginResp> accountLogin(@Validated @RequestBody AccountLoginReq loginReq) {
|
||||
public R<LoginResp> accountLogin(@Validated @RequestBody AccountLoginReq loginReq, HttpServletRequest request) {
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + loginReq.getUuid();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
@@ -77,21 +78,7 @@ public class AuthController {
|
||||
// 用户登录
|
||||
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(loginReq.getPassword()));
|
||||
ValidationUtils.throwIfBlank(rawPassword, "密码解密失败");
|
||||
String token = loginService.accountLogin(loginReq.getUsername(), rawPassword);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "邮箱登录", description = "根据邮箱和验证码进行登录认证")
|
||||
@PostMapping("/email")
|
||||
public R<LoginResp> emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
|
||||
String email = loginReq.getEmail();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
|
||||
RedisUtils.delete(captchaKey);
|
||||
String token = loginService.emailLogin(email);
|
||||
String token = loginService.accountLogin(loginReq.getUsername(), rawPassword, request);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@@ -109,6 +96,20 @@ public class AuthController {
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "邮箱登录", description = "根据邮箱和验证码进行登录认证")
|
||||
@PostMapping("/email")
|
||||
public R<LoginResp> emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
|
||||
String email = loginReq.getEmail();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
|
||||
RedisUtils.delete(captchaKey);
|
||||
String token = loginService.emailLogin(email);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@Operation(summary = "用户退出", description = "注销用户的当前登录")
|
||||
@Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER)
|
||||
@PostMapping("/logout")
|
||||
|
@@ -61,7 +61,7 @@ public class UserController extends BaseController<UserService, UserResp, UserDe
|
||||
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword()));
|
||||
ValidationUtils.throwIfNull(rawPassword, "密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
|
||||
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||
req.setPassword(rawPassword);
|
||||
return super.add(req);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class UserController extends BaseController<UserService, UserResp, UserDe
|
||||
String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getNewPassword()));
|
||||
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
|
||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||
req.setNewPassword(rawNewPassword);
|
||||
baseService.resetPassword(req, id);
|
||||
return R.ok("重置密码成功");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- liquibase formatted sql
|
||||
|
||||
-- changeset Charles7c:2.5.0
|
||||
-- changeset Charles7c:1
|
||||
-- comment 初始化表数据
|
||||
-- 初始化默认菜单
|
||||
INSERT INTO `sys_menu`
|
||||
@@ -109,19 +109,20 @@ VALUES
|
||||
INSERT INTO `sys_option`
|
||||
(`name`, `code`, `value`, `default_value`, `description`, `update_user`, `update_time`)
|
||||
VALUES
|
||||
('系统标题', 'site_title', NULL, 'ContiNew Admin', '用于显示登录页面的系统标题。', NULL, NULL),
|
||||
('版权信息', 'site_copyright', NULL,
|
||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
||||
('系统标题', 'SITE_TITLE', NULL, 'ContiNew Admin', '用于显示登录页面的系统标题。', NULL, NULL),
|
||||
('版权信息', 'SITE_COPYRIGHT', NULL,
|
||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-3</a>',
|
||||
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
||||
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||
('密码是否允许包含正反序帐户名', 'password_contain_name', NULL, '0', '', NULL, NULL),
|
||||
('密码错误锁定帐户次数', 'password_error_count', NULL, '5', '0表示不限制。', NULL, NULL),
|
||||
('密码有效期', 'password_expiration_days', NULL, '0', '取值范围为0-999,0表示永久有效。', NULL, NULL),
|
||||
('密码错误锁定帐户的时间', 'password_lock_minutes', NULL, '5', '0表示不解锁。', NULL, NULL),
|
||||
('密码最小长度', 'password_min_length', NULL, '8', '取值范围为8-32。', NULL, NULL),
|
||||
('密码是否必须包含特殊字符', 'password_special_char', NULL, '0', '', NULL, NULL),
|
||||
('修改密码最短间隔', 'password_update_interval', NULL, '5', '取值范围为0-9999,0表示不限制。', NULL, NULL);
|
||||
('系统LOGO(16*16)', 'SITE_FAVICON', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||
('系统LOGO(33*33)', 'SITE_LOGO', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||
('登录密码错误锁定账号的次数', 'PASSWORD_ERROR_LOCK_COUNT', NULL, '5', '取值范围为 0-10(0 表示不锁定)。', NULL, NULL),
|
||||
('登录密码错误锁定账号的时间(min)', 'PASSWORD_ERROR_LOCK_MINUTES', NULL, '5', '取值范围为 1-1440(一天)。', NULL, NULL),
|
||||
('密码到期提前提示(天)', 'PASSWORD_EXPIRATION_WARNING_DAYS', NULL, '0', '密码到期 N 天前进行提示(0 表示不提示)。', NULL, NULL),
|
||||
('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL),
|
||||
('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL),
|
||||
('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL),
|
||||
('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '0', '', NULL, NULL),
|
||||
('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL);
|
||||
|
||||
-- 初始化默认字典
|
||||
INSERT INTO `sys_dict`
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- liquibase formatted sql
|
||||
|
||||
-- changeset Charles7c:2.5.0
|
||||
-- changeset Charles7c:1
|
||||
-- comment 初始化表结构
|
||||
CREATE TABLE IF NOT EXISTS `sys_menu` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'ID',
|
||||
@@ -256,19 +256,19 @@ CREATE TABLE IF NOT EXISTS `sys_storage` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='存储表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sys_file` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'ID',
|
||||
`name` varchar(255) NOT NULL COMMENT '名称',
|
||||
`size` bigint(20) NOT NULL COMMENT '大小(字节)',
|
||||
`url` varchar(512) NOT NULL COMMENT 'URL',
|
||||
`extension` varchar(100) DEFAULT NULL COMMENT '扩展名',
|
||||
`type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(1:其他;2:图片;3:文档;4:视频;5:音频)',
|
||||
`storage_id` bigint(20) NOT NULL COMMENT '存储ID',
|
||||
`create_user` bigint(20) NOT NULL COMMENT '创建人',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_user` bigint(20) NOT NULL COMMENT '修改人',
|
||||
`update_time` datetime NOT NULL COMMENT '修改时间',
|
||||
`thumbnail_size` bigint(20) NULL DEFAULT NULL COMMENT '缩略图大小(字节)',
|
||||
`thumbnail_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缩略图URL',
|
||||
`id` bigint(20) NOT NULL COMMENT 'ID',
|
||||
`name` varchar(255) NOT NULL COMMENT '名称',
|
||||
`size` bigint(20) NOT NULL COMMENT '大小(字节)',
|
||||
`url` varchar(512) NOT NULL COMMENT 'URL',
|
||||
`extension` varchar(100) DEFAULT NULL COMMENT '扩展名',
|
||||
`thumbnail_size` bigint(20) DEFAULT NULL COMMENT '缩略图大小(字节)',
|
||||
`thumbnail_url` varchar(512) DEFAULT NULL COMMENT '缩略图URL',
|
||||
`type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(1:其他;2:图片;3:文档;4:视频;5:音频)',
|
||||
`storage_id` bigint(20) NOT NULL COMMENT '存储ID',
|
||||
`create_user` bigint(20) NOT NULL COMMENT '创建人',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_user` bigint(20) NOT NULL COMMENT '修改人',
|
||||
`update_time` datetime NOT NULL COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_url`(`url`) USING BTREE,
|
||||
INDEX `idx_type`(`type`) USING BTREE,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- liquibase formatted sql
|
||||
|
||||
-- changeset Charles7c:2.5.0
|
||||
-- changeset Charles7c:1
|
||||
-- comment 初始化表数据
|
||||
-- 初始化默认菜单
|
||||
INSERT INTO "sys_menu"
|
||||
@@ -109,19 +109,20 @@ VALUES
|
||||
INSERT INTO "sys_option"
|
||||
("name", "code", "value", "default_value", "description", "update_user", "update_time")
|
||||
VALUES
|
||||
('系统标题', 'site_title', NULL, 'ContiNew Admin', '用于显示登录页面的系统标题。', NULL, NULL),
|
||||
('版权信息', 'site_copyright', NULL,
|
||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
||||
('系统标题', 'SITE_TITLE', NULL, 'ContiNew Admin', '用于显示登录页面的系统标题。', NULL, NULL),
|
||||
('版权信息', 'SITE_COPYRIGHT', NULL,
|
||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-3</a>',
|
||||
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
||||
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||
('密码是否允许包含正反序帐户名', 'password_contain_name', NULL, '0', '', NULL, NULL),
|
||||
('密码错误锁定帐户次数', 'password_error_count', NULL, '5', '0表示不限制。', NULL, NULL),
|
||||
('密码有效期', 'password_expiration_days', NULL, '0', '取值范围为0-999,0表示永久有效。', NULL, NULL),
|
||||
('密码错误锁定帐户的时间', 'password_lock_minutes', NULL, '5', '0表示不解锁。', NULL, NULL),
|
||||
('密码最小长度', 'password_min_length', NULL, '8', '取值范围为8-32。', NULL, NULL),
|
||||
('密码是否必须包含特殊字符', 'password_special_char', NULL, '0', '', NULL, NULL),
|
||||
('修改密码最短间隔', 'password_update_interval', NULL, '5', '取值范围为0-9999,0表示不限制。', NULL, NULL);
|
||||
('系统LOGO(16*16)', 'SITE_FAVICON', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||
('系统LOGO(33*33)', 'SITE_LOGO', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||
('登录密码错误锁定账号的次数', 'PASSWORD_ERROR_LOCK_COUNT', NULL, '5', '取值范围为 0-10(0 表示不锁定)。', NULL, NULL),
|
||||
('登录密码错误锁定账号的时间(min)', 'PASSWORD_ERROR_LOCK_MINUTES', NULL, '5', '取值范围为 1-1440(一天)。', NULL, NULL),
|
||||
('密码到期提前提示(天)', 'PASSWORD_EXPIRATION_WARNING_DAYS', NULL, '0', '密码到期 N 天前进行提示(0 表示不提示)。', NULL, NULL),
|
||||
('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL),
|
||||
('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL),
|
||||
('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL),
|
||||
('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '0', '', NULL, NULL),
|
||||
('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL);
|
||||
|
||||
-- 初始化默认字典
|
||||
INSERT INTO "sys_dict"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
-- liquibase formatted sql
|
||||
|
||||
-- changeset Charles7c:2.5.0
|
||||
-- changeset Charles7c:1
|
||||
-- comment 初始化表结构
|
||||
CREATE TABLE IF NOT EXISTS "sys_menu" (
|
||||
"id" int8 NOT NULL,
|
||||
@@ -430,39 +430,39 @@ COMMENT ON COLUMN "sys_storage"."update_time" IS '修改时间';
|
||||
COMMENT ON TABLE "sys_storage" IS '存储表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "sys_file" (
|
||||
"id" int8 NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"size" int8 NOT NULL,
|
||||
"url" varchar(512) NOT NULL,
|
||||
"extension" varchar(100) DEFAULT NULL,
|
||||
"type" int2 NOT NULL DEFAULT 1,
|
||||
"storage_id" int8 NOT NULL,
|
||||
"create_user" int8 NOT NULL,
|
||||
"create_time" timestamp NOT NULL,
|
||||
"update_user" int8 NOT NULL,
|
||||
"update_time" timestamp NOT NULL,
|
||||
"thumbnail_size" int8 DEFAULT NULL,
|
||||
"thumbnail_url" varchar(512) DEFAULT NULL,
|
||||
"id" int8 NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"size" int8 NOT NULL,
|
||||
"url" varchar(512) NOT NULL,
|
||||
"extension" varchar(100) DEFAULT NULL,
|
||||
"thumbnail_size" int8 DEFAULT NULL,
|
||||
"thumbnail_url" varchar(512) DEFAULT NULL,
|
||||
"type" int2 NOT NULL DEFAULT 1,
|
||||
"storage_id" int8 NOT NULL,
|
||||
"create_user" int8 NOT NULL,
|
||||
"create_time" timestamp NOT NULL,
|
||||
"update_user" int8 NOT NULL,
|
||||
"update_time" timestamp NOT NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
CREATE INDEX "idx_file_url" ON "sys_file" ("url");
|
||||
CREATE INDEX "idx_file_type" ON "sys_file" ("type");
|
||||
CREATE INDEX "idx_file_create_user" ON "sys_file" ("create_user");
|
||||
CREATE INDEX "idx_file_update_user" ON "sys_file" ("update_user");
|
||||
COMMENT ON COLUMN "sys_file"."id" IS 'ID';
|
||||
COMMENT ON COLUMN "sys_file"."name" IS '名称';
|
||||
COMMENT ON COLUMN "sys_file"."size" IS '大小(字节)';
|
||||
COMMENT ON COLUMN "sys_file"."url" IS 'URL';
|
||||
COMMENT ON COLUMN "sys_file"."extension" IS '扩展名';
|
||||
COMMENT ON COLUMN "sys_file"."type" IS '类型(1:其他;2:图片;3:文档;4:视频;5:音频)';
|
||||
COMMENT ON COLUMN "sys_file"."storage_id" IS '存储ID';
|
||||
COMMENT ON COLUMN "sys_file"."create_user" IS '创建人';
|
||||
COMMENT ON COLUMN "sys_file"."create_time" IS '创建时间';
|
||||
COMMENT ON COLUMN "sys_file"."update_user" IS '修改人';
|
||||
COMMENT ON COLUMN "sys_file"."update_time" IS '修改时间';
|
||||
COMMENT ON COLUMN "sys_file"."id" IS 'ID';
|
||||
COMMENT ON COLUMN "sys_file"."name" IS '名称';
|
||||
COMMENT ON COLUMN "sys_file"."size" IS '大小(字节)';
|
||||
COMMENT ON COLUMN "sys_file"."url" IS 'URL';
|
||||
COMMENT ON COLUMN "sys_file"."extension" IS '扩展名';
|
||||
COMMENT ON COLUMN "sys_file"."thumbnail_size" IS '缩略图大小(字节)';
|
||||
COMMENT ON COLUMN "sys_file"."thumbnail_url" IS '缩略图URL';
|
||||
COMMENT ON TABLE "sys_file" IS '文件表';
|
||||
COMMENT ON COLUMN "sys_file"."thumbnail_url" IS '缩略图URL';
|
||||
COMMENT ON COLUMN "sys_file"."type" IS '类型(1:其他;2:图片;3:文档;4:视频;5:音频)';
|
||||
COMMENT ON COLUMN "sys_file"."storage_id" IS '存储ID';
|
||||
COMMENT ON COLUMN "sys_file"."create_user" IS '创建人';
|
||||
COMMENT ON COLUMN "sys_file"."create_time" IS '创建时间';
|
||||
COMMENT ON COLUMN "sys_file"."update_user" IS '修改人';
|
||||
COMMENT ON COLUMN "sys_file"."update_time" IS '修改时间';
|
||||
COMMENT ON TABLE "sys_file" IS '文件表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "gen_config" (
|
||||
"table_name" varchar(64) NOT NULL,
|
||||
|
Reference in New Issue
Block a user