fix: simplify account password flow

This commit is contained in:
inman committed 2026-09-02 11:15:30 +08:00
1 parent 203bfb3246
commit df65e9f517
9 files changed
+118 -131

No files matched your search

+14 -33
View File
@@ -51,19 +51,18 @@ export function aiServiceConnected(databaseIsReady: boolean, probe: Record<strin
const loginSchema = z.object({
username: z.string().min(1).max(160),
password: z.string().min(1).max(512)
password: z.string().min(1)
});
const changePasswordSchema = z.object({
current_password: z.string().min(1).max(512),
new_password: z.string().min(12).max(512)
current_password: z.string().min(1),
new_password: z.string().min(1)
});
const accountCreateSchema = z.object({
username: z.string().min(1).max(160),
password: z.string().min(12).max(512),
password: z.string().min(1),
role: z.enum(['admin', 'team_lead', 'user']).default('user'),
must_change_password: z.boolean().default(true),
business_route_ids: z.array(
z.string().trim().refine((routeId) => Boolean(businessRouteById(routeId)), '业务类型不存在。')
).max(BUSINESS_ROUTES.length).default([])
@@ -78,8 +77,7 @@ const accountUpdateSchema = z.object({
});
const accountPasswordResetSchema = z.object({
password: z.string().min(12).max(512),
must_change_password: z.boolean().default(true)
password: z.string().min(1)
});
const accountBusinessAuthorizationsSchema = z.object({
@@ -363,8 +361,7 @@ function publicUser(session: ActiveSession) {
return {
id: session.user.id,
username: session.user.username,
role: session.user.role,
must_change_password: session.user.mustChangePassword
role: session.user.role
};
}
@@ -516,14 +513,6 @@ export async function buildServer({
return session;
};
const getReadySession = async (request: FastifyRequest): Promise<ActiveSession> => {
const session = await getSession(request);
if (session.user.mustChangePassword) {
throw new AuthError('password_change_required', '首次登录或密码重置后必须先修改密码。', 403);
}
return session;
};
const requireAdmin = (session: ActiveSession): ActiveSession => {
if (session.user.role !== 'admin') throw new AuthError('admin_required', '需要管理员权限。', 403);
return session;
@@ -554,16 +543,10 @@ export async function buildServer({
return session;
};
const requireMutationSession = async (request: FastifyRequest): Promise<ActiveSession> => {
const session = await requireAuthenticatedMutationSession(request);
if (session.user.mustChangePassword) {
throw new AuthError('password_change_required', '首次登录或密码重置后必须先修改密码。', 403);
}
return session;
};
const requireMutationSession = requireAuthenticatedMutationSession;
const requireAdminSession = async (request: FastifyRequest): Promise<ActiveSession> => (
requireAdmin(await getReadySession(request))
requireAdmin(await getSession(request))
);
const requireAdminMutationSession = async (request: FastifyRequest): Promise<ActiveSession> => (
@@ -571,7 +554,7 @@ export async function buildServer({
);
const requireLeadershipSession = async (request: FastifyRequest): Promise<ActiveSession> => (
requireLeadership(await getReadySession(request))
requireLeadership(await getSession(request))
);
async function persistParseOutcome(
@@ -980,7 +963,6 @@ export async function buildServer({
username: body.username,
password: body.password,
role: body.role,
mustChangePassword: body.must_change_password,
businessRouteIds: body.business_route_ids
}, requestId(request));
return { ok: true, account };
@@ -1022,7 +1004,6 @@ export async function buildServer({
session.user,
userId,
body.password,
body.must_change_password,
requestId(request)
);
return { ok: true, password_reset: true, sessions_revoked: true };
@@ -1172,7 +1153,7 @@ export async function buildServer({
});
app.get('/api/tasks', async (request) => {
const session = await getReadySession(request);
const session = await getSession(request);
const query = listTasksQuerySchema.parse(request.query || {});
const page = await tasks.listTasksPage(session.user.organizationId, {
status: query.status || undefined,
@@ -1224,19 +1205,19 @@ export async function buildServer({
});
app.get('/api/tasks/:taskId', async (request) => {
const session = await getReadySession(request);
const session = await getSession(request);
const params = request.params as { taskId: string };
return { ok: true, task: await tasks.getTask(session.user.organizationId, params.taskId, contextFor(session, request)) };
});
app.get('/api/tasks/:taskId/input-history', async (request) => {
const session = await getReadySession(request);
const session = await getSession(request);
const params = request.params as { taskId: string };
return { ok: true, ...(await tasks.getTaskInputHistory(contextFor(session, request), params.taskId)) };
});
app.get('/api/tasks/:taskId/artifacts/:artifactId', async (request, reply) => {
const session = await getReadySession(request);
const session = await getSession(request);
const params = request.params as { taskId: string; artifactId: string };
const artifactId = z.string().uuid().safeParse(params.artifactId);
if (!artifactId.success) throw new TaskError('artifact_not_found', '附件不存在或无权访问。', 404);
@@ -1403,7 +1384,7 @@ export async function buildServer({
});
app.get('/api/events', async (request, reply) => {
const session = await getReadySession(request);
const session = await getSession(request);
const query = (request.query || {}) as Record<string, unknown>;
const querySince = Number(query.since || 0);
const reconnectSince = Number(request.headers['last-event-id'] || 0);