mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-01-16 05:10:34 +00:00
feat: 更新密码功能增强,添加新密码强度验证和旧密码检查
This commit is contained in:
parent
5499b5fbc9
commit
d3013e32e1
@ -14,8 +14,9 @@ const ChangePasswordCard = () => {
|
|||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit: handleWebuiSubmit,
|
handleSubmit: handleWebuiSubmit,
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting, errors },
|
||||||
reset
|
reset,
|
||||||
|
watch
|
||||||
} = useForm<{
|
} = useForm<{
|
||||||
oldToken: string
|
oldToken: string
|
||||||
newToken: string
|
newToken: string
|
||||||
@ -29,6 +30,9 @@ const ChangePasswordCard = () => {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [_, setToken] = useLocalStorage(key.token, '')
|
const [_, setToken] = useLocalStorage(key.token, '')
|
||||||
|
|
||||||
|
// 监听旧密码的值
|
||||||
|
const oldTokenValue = watch('oldToken')
|
||||||
|
|
||||||
const onSubmit = handleWebuiSubmit(async (data) => {
|
const onSubmit = handleWebuiSubmit(async (data) => {
|
||||||
try {
|
try {
|
||||||
// 使用正常密码更新流程
|
// 使用正常密码更新流程
|
||||||
@ -51,12 +55,24 @@ const ChangePasswordCard = () => {
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="oldToken"
|
name="oldToken"
|
||||||
|
rules={{
|
||||||
|
required: '旧密码不能为空',
|
||||||
|
validate: (value) => {
|
||||||
|
if (!value || value.trim().length === 0) {
|
||||||
|
return '旧密码不能为空'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
label="旧密码"
|
label="旧密码"
|
||||||
placeholder="请输入旧密码"
|
placeholder="请输入旧密码"
|
||||||
type="password"
|
type="password"
|
||||||
|
isRequired
|
||||||
|
isInvalid={!!errors.oldToken}
|
||||||
|
errorMessage={errors.oldToken?.message}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -64,12 +80,42 @@ const ChangePasswordCard = () => {
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="newToken"
|
name="newToken"
|
||||||
|
rules={{
|
||||||
|
required: '新密码不能为空',
|
||||||
|
minLength: {
|
||||||
|
value: 6,
|
||||||
|
message: '新密码至少需要6个字符'
|
||||||
|
},
|
||||||
|
validate: (value) => {
|
||||||
|
if (!value || value.trim().length === 0) {
|
||||||
|
return '新密码不能为空'
|
||||||
|
}
|
||||||
|
if (value.trim().length !== value.length) {
|
||||||
|
return '新密码不能包含前后空格'
|
||||||
|
}
|
||||||
|
if (value === oldTokenValue) {
|
||||||
|
return '新密码不能与旧密码相同'
|
||||||
|
}
|
||||||
|
// 检查是否包含字母
|
||||||
|
if (!/[a-zA-Z]/.test(value)) {
|
||||||
|
return '新密码必须包含字母'
|
||||||
|
}
|
||||||
|
// 检查是否包含数字
|
||||||
|
if (!/[0-9]/.test(value)) {
|
||||||
|
return '新密码必须包含数字'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
label="新密码"
|
label="新密码"
|
||||||
placeholder="请输入新密码"
|
placeholder="至少6位,包含字母和数字"
|
||||||
type="password"
|
type="password"
|
||||||
|
isRequired
|
||||||
|
isInvalid={!!errors.newToken}
|
||||||
|
errorMessage={errors.newToken?.message}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -92,16 +92,36 @@ export const checkHandler: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
// 修改密码(token)
|
// 修改密码(token)
|
||||||
export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
||||||
const { oldToken, newToken, fromDefault } = req.body;
|
const { oldToken, newToken } = req.body;
|
||||||
const authorization = req.headers.authorization;
|
const authorization = req.headers.authorization;
|
||||||
|
|
||||||
if (isEmpty(newToken)) {
|
if (isEmpty(newToken)) {
|
||||||
return sendError(res, 'newToken is empty');
|
return sendError(res, 'newToken is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果不是从默认密码更新,则需要验证旧密码
|
// 强制要求旧密码
|
||||||
if (!fromDefault && isEmpty(oldToken)) {
|
if (isEmpty(oldToken)) {
|
||||||
return sendError(res, 'oldToken is required when not updating from default password');
|
return sendError(res, 'oldToken is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查新旧密码是否相同
|
||||||
|
if (oldToken === newToken) {
|
||||||
|
return sendError(res, '新密码不能与旧密码相同');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查新密码强度
|
||||||
|
if (newToken.length < 6) {
|
||||||
|
return sendError(res, '新密码至少需要6个字符');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否包含字母
|
||||||
|
if (!/[a-zA-Z]/.test(newToken)) {
|
||||||
|
return sendError(res, '新密码必须包含字母');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否包含数字
|
||||||
|
if (!/[0-9]/.test(newToken)) {
|
||||||
|
return sendError(res, '新密码必须包含数字');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -112,29 +132,18 @@ export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
|||||||
AuthHelper.revokeCredential(Credential);
|
AuthHelper.revokeCredential(Credential);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromDefault) {
|
// 使用启动时缓存的token进行验证
|
||||||
// 从默认密码更新,直接设置新密码
|
const initialToken = getInitialWebUiToken();
|
||||||
const currentConfig = await WebUiConfig.GetWebUIConfig();
|
if (!initialToken) {
|
||||||
if (!currentConfig.defaultToken) {
|
return sendError(res, 'Server token not initialized');
|
||||||
return sendError(res, 'Current password is not default password');
|
|
||||||
}
|
|
||||||
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
|
||||||
// 更新内存中的缓存token,使新密码立即生效
|
|
||||||
setInitialWebUiToken(newToken);
|
|
||||||
} else {
|
|
||||||
// 正常的密码更新流程 - 使用启动时缓存的token进行验证
|
|
||||||
const initialToken = getInitialWebUiToken();
|
|
||||||
if (!initialToken) {
|
|
||||||
return sendError(res, 'Server token not initialized');
|
|
||||||
}
|
|
||||||
if (initialToken !== oldToken) {
|
|
||||||
return sendError(res, '旧 token 不匹配');
|
|
||||||
}
|
|
||||||
// 直接更新配置文件中的token,不需要通过WebUiConfig.UpdateToken方法
|
|
||||||
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
|
||||||
// 更新内存中的缓存token,使新密码立即生效
|
|
||||||
setInitialWebUiToken(newToken);
|
|
||||||
}
|
}
|
||||||
|
if (initialToken !== oldToken) {
|
||||||
|
return sendError(res, '旧 token 不匹配');
|
||||||
|
}
|
||||||
|
// 直接更新配置文件中的token,不需要通过WebUiConfig.UpdateToken方法
|
||||||
|
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
||||||
|
// 更新内存中的缓存token,使新密码立即生效
|
||||||
|
setInitialWebUiToken(newToken);
|
||||||
|
|
||||||
return sendSuccess(res, 'Token updated successfully');
|
return sendSuccess(res, 'Token updated successfully');
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CheckDefaultTokenHandler,
|
|
||||||
checkHandler,
|
checkHandler,
|
||||||
LoginHandler,
|
LoginHandler,
|
||||||
LogoutHandler,
|
LogoutHandler,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user