All checks were successful
CI / build-and-deploy (push) Successful in 1m22s
Den Zeitraum-Bereich habe ich dabei gleich mit aufgeräumt: die Auswahl des aktuellen Haushalts ist breiter und sauberer angeordnet, und die Desktop-Nutzerverwaltung ist jetzt wirklich links Anlegen + Schwelle und rechts die Nutzerliste. Seed und Backup/Restore kennen die neuen Felder ebenfalls in seed.ts, route.ts und route.ts.
93 lines
2.5 KiB
TypeScript
93 lines
2.5 KiB
TypeScript
import type { NextAuthOptions } from "next-auth";
|
|
import CredentialsProvider from "next-auth/providers/credentials";
|
|
import bcrypt from "bcryptjs";
|
|
import { z } from "zod";
|
|
|
|
import { normalizeApprovalPermissions } from "@/lib/domain";
|
|
import prisma from "@/lib/prisma";
|
|
|
|
const credentialsSchema = z.object({
|
|
identifier: z.string().trim().min(2),
|
|
password: z.string().min(6)
|
|
});
|
|
|
|
export const authOptions: NextAuthOptions = {
|
|
session: {
|
|
strategy: "jwt"
|
|
},
|
|
pages: {
|
|
signIn: "/login"
|
|
},
|
|
providers: [
|
|
CredentialsProvider({
|
|
name: "Login und Passwort",
|
|
credentials: {
|
|
identifier: { label: "Login-Name", type: "text" },
|
|
password: { label: "Passwort", type: "password" }
|
|
},
|
|
async authorize(rawCredentials) {
|
|
const parsedCredentials = credentialsSchema.safeParse(rawCredentials);
|
|
|
|
if (!parsedCredentials.success) {
|
|
return null;
|
|
}
|
|
|
|
const normalizedIdentifier = parsedCredentials.data.identifier.toLowerCase();
|
|
const matchedUser = await prisma.user.findUnique({
|
|
where: {
|
|
username: normalizedIdentifier
|
|
}
|
|
});
|
|
|
|
if (!matchedUser) {
|
|
return null;
|
|
}
|
|
|
|
const isPasswordValid = await bcrypt.compare(parsedCredentials.data.password, matchedUser.passwordHash);
|
|
|
|
if (!isPasswordValid) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
id: matchedUser.id,
|
|
name: matchedUser.username,
|
|
username: matchedUser.username,
|
|
email: matchedUser.email,
|
|
role: matchedUser.role,
|
|
workingGroupId: matchedUser.workingGroupId,
|
|
approvalPermissions: normalizeApprovalPermissions(
|
|
matchedUser.role,
|
|
matchedUser.approvalPermissions,
|
|
matchedUser.approvalPreference
|
|
)
|
|
};
|
|
}
|
|
})
|
|
],
|
|
callbacks: {
|
|
async jwt({ token, user }) {
|
|
if (user) {
|
|
token.id = user.id;
|
|
token.username = user.username;
|
|
token.role = user.role;
|
|
token.workingGroupId = user.workingGroupId;
|
|
token.approvalPermissions = user.approvalPermissions;
|
|
}
|
|
|
|
return token;
|
|
},
|
|
async session({ session, token }) {
|
|
if (session.user) {
|
|
session.user.id = token.id ?? "";
|
|
session.user.username = token.username ?? "";
|
|
session.user.role = token.role ?? "MEMBER";
|
|
session.user.workingGroupId = token.workingGroupId ?? null;
|
|
session.user.approvalPermissions = token.approvalPermissions ?? [];
|
|
}
|
|
|
|
return session;
|
|
}
|
|
}
|
|
};
|