fix: lower admin password minimum
This commit is contained in:
@@ -28,7 +28,7 @@ async function load() {
|
||||
}
|
||||
|
||||
async function createAccount() {
|
||||
if (form.password.length < 12) return message.error('初始密码至少 12 位')
|
||||
if (form.password.length < 6 || form.password.length > 128) return message.error('初始密码必须为 6 到 128 位')
|
||||
await api.createAdminAccount(form)
|
||||
message.success('管理员已创建')
|
||||
createOpen.value = false
|
||||
@@ -50,7 +50,9 @@ async function update(account: Account, patch: Partial<Account>) {
|
||||
}
|
||||
|
||||
async function submitReset() {
|
||||
if (!resetTarget.value || resetPassword.value.length < 12) return message.error('新密码至少 12 位')
|
||||
if (!resetTarget.value || resetPassword.value.length < 6 || resetPassword.value.length > 128) {
|
||||
return message.error('新密码必须为 6 到 128 位')
|
||||
}
|
||||
await api.resetAdminPassword(resetTarget.value.id, resetPassword.value)
|
||||
message.success('密码已重置,现有会话已撤销')
|
||||
resetTarget.value = null
|
||||
@@ -110,7 +112,7 @@ onMounted(load)
|
||||
<a-modal v-model:open="createOpen" title="新建管理员" ok-text="创建" @ok="createAccount">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="用户名"><a-input v-model:value="form.username" /></a-form-item>
|
||||
<a-form-item label="初始密码"><a-input-password v-model:value="form.password" /></a-form-item>
|
||||
<a-form-item label="初始密码"><a-input-password v-model:value="form.password" :maxlength="128" /></a-form-item>
|
||||
<a-form-item label="角色">
|
||||
<a-select v-model:value="form.role">
|
||||
<a-select-option value="operator">operator</a-select-option>
|
||||
@@ -123,7 +125,7 @@ onMounted(load)
|
||||
|
||||
<a-modal :open="!!resetTarget" title="重置密码" ok-text="重置并撤销会话"
|
||||
@cancel="resetTarget = null" @ok="submitReset">
|
||||
<a-input-password v-model:value="resetPassword" placeholder="至少 12 位的新密码" />
|
||||
<a-input-password v-model:value="resetPassword" :maxlength="128" placeholder="6 到 128 位的新密码" />
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ const loading = ref(false)
|
||||
async function submit() {
|
||||
if (loading.value) return
|
||||
if (!form.currentPassword) return message.error('请输入当前密码')
|
||||
if (form.newPassword.length < 12 || form.newPassword.length > 128) {
|
||||
return message.error('新密码长度必须为 12 到 128 位')
|
||||
if (form.newPassword.length < 6 || form.newPassword.length > 128) {
|
||||
return message.error('新密码长度必须为 6 到 128 位')
|
||||
}
|
||||
if (form.newPassword !== form.confirmPassword) return message.error('两次输入的新密码不一致')
|
||||
loading.value = true
|
||||
@@ -43,12 +43,13 @@ async function logout() {
|
||||
<a-input-password v-model:value="form.currentPassword" autocomplete="current-password" />
|
||||
</a-form-item>
|
||||
<a-form-item label="新密码" required>
|
||||
<a-input-password v-model:value="form.newPassword" autocomplete="new-password" />
|
||||
<a-input-password v-model:value="form.newPassword" autocomplete="new-password" :maxlength="128" />
|
||||
</a-form-item>
|
||||
<a-form-item label="确认新密码" required>
|
||||
<a-input-password
|
||||
v-model:value="form.confirmPassword"
|
||||
autocomplete="new-password"
|
||||
:maxlength="128"
|
||||
@pressEnter="submit"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
@@ -664,8 +664,12 @@ public sealed class ApiIntegrationTests(ApiFixture fixture)
|
||||
using var superAdmin = await fixture.AdminAsync();
|
||||
var suffix = Guid.NewGuid().ToString("N")[..10];
|
||||
var username = $"viewer_{suffix}";
|
||||
const string initialPassword = "viewer-initial-password-123";
|
||||
const string permanentPassword = "viewer-permanent-password-456";
|
||||
const string initialPassword = "init06";
|
||||
const string permanentPassword = "new006";
|
||||
var shortPasswordResponse = await superAdmin.PostAsJsonAsync(
|
||||
"/api/admin/security/accounts",
|
||||
new { username = $"{username}_short", password = "12345", role = "viewer" });
|
||||
Assert.Equal(HttpStatusCode.BadRequest, shortPasswordResponse.StatusCode);
|
||||
var createdResponse = await superAdmin.PostAsJsonAsync(
|
||||
"/api/admin/security/accounts",
|
||||
new { username, password = initialPassword, role = "viewer" });
|
||||
|
||||
@@ -37,7 +37,8 @@ public sealed class AdminAccountsController(AppDbContext db) : ControllerBase
|
||||
public async Task<IActionResult> Create(CreateAdminUserRequest request, CancellationToken ct)
|
||||
{
|
||||
var username = request.Username.Trim();
|
||||
if (username.Length is < 3 or > 64 || request.Password.Length is < 12 or > 128 ||
|
||||
if (username.Length is < 3 or > 64 ||
|
||||
request.Password.Length is < AdminPasswordPolicy.MinLength or > AdminPasswordPolicy.MaxLength ||
|
||||
!AdminRoles.All.Contains(request.Role))
|
||||
return BadRequest(new ApiError("ADMIN_ACCOUNT_INVALID", "管理员账号、密码或角色无效"));
|
||||
if (await db.AdminUsers.AnyAsync(item => item.Username == username, ct))
|
||||
@@ -90,8 +91,8 @@ public sealed class AdminAccountsController(AppDbContext db) : ControllerBase
|
||||
ResetAdminPasswordRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (request.Password.Length is < 12 or > 128)
|
||||
return BadRequest(new ApiError("ADMIN_PASSWORD_INVALID", "密码长度必须为 12 到 128 位"));
|
||||
if (request.Password.Length is < AdminPasswordPolicy.MinLength or > AdminPasswordPolicy.MaxLength)
|
||||
return BadRequest(new ApiError("ADMIN_PASSWORD_INVALID", "密码长度必须为 6 到 128 位"));
|
||||
var user = await db.AdminUsers.FindAsync([id], ct);
|
||||
if (user is null) return NotFound();
|
||||
user.PasswordHash = AdminSessionService.HashPassword(request.Password);
|
||||
|
||||
@@ -53,8 +53,9 @@ public sealed class AdminAuthController(
|
||||
AdminChangePasswordRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (request.NewPassword.Length < 12 || request.NewPassword.Length > 128)
|
||||
return BadRequest(new ApiError("ADMIN_PASSWORD_INVALID", "新密码长度必须为 12 到 128 位"));
|
||||
if (request.NewPassword.Length < AdminPasswordPolicy.MinLength ||
|
||||
request.NewPassword.Length > AdminPasswordPolicy.MaxLength)
|
||||
return BadRequest(new ApiError("ADMIN_PASSWORD_INVALID", "新密码长度必须为 6 到 128 位"));
|
||||
var principal = AdminRequestContext.Principal(HttpContext)!;
|
||||
var user = await db.AdminUsers.FirstAsync(item => item.Id == principal.UserId, ct);
|
||||
if (!BCrypt.Net.BCrypt.Verify(request.CurrentPassword, user.PasswordHash))
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed class AdminBootstrapService(
|
||||
var username = configuration["Admin:BootstrapUsername"]?.Trim();
|
||||
var password = configuration["Admin:BootstrapPassword"];
|
||||
if (string.IsNullOrWhiteSpace(username) || username.Length is < 3 or > 64 ||
|
||||
string.IsNullOrWhiteSpace(password) || password.Length < 12)
|
||||
string.IsNullOrWhiteSpace(password) || password.Length < AdminPasswordPolicy.MinLength)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"首次启动必须通过 Admin__BootstrapUsername 和 Admin__BootstrapPassword 配置管理员,密码至少 12 位");
|
||||
"首次启动必须通过 Admin__BootstrapUsername 和 Admin__BootstrapPassword 配置管理员,密码至少 6 位");
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace MiaoJiZhang.Api.Services;
|
||||
|
||||
public static class AdminPasswordPolicy
|
||||
{
|
||||
public const int MinLength = 6;
|
||||
public const int MaxLength = 128;
|
||||
}
|
||||
Reference in New Issue
Block a user