refactor(quick-260921-m34): Aufgabe 2a - gemeinsamer Aufrufer-Typ, aus den Signierstellen abgeleitet
apps/api/src/auth/types/auth-user.ts angelegt: AuthUser, AuthenticatedRequest, LocalAuthenticatedRequest, LoginUser, JwtPayload, UploadedFileLike. Jedes Feld traegt seine Herkunft als Kommentar. tenantId ist string, hergeleitet und nicht gewaehlt: die Spalte User.tenantId ist in schema.prisma Pflicht, beide Signierstellen schreiben genau sie, und der Bestand beschreibt dasselbe Objekt in SessionUser schon so. Der SUPER_ADMIN-Zweig in TenantGuard spricht nicht dagegen - der Waechter liest AuthUser gar nicht, und dass es den Zweig gibt, steht als null in AuthenticatedRequest.tenantId weiter im Typsystem. tenant.guard.ts bleibt unberuehrt. role ist die Aufzaehlung Role: schema.prisma deklariert die Spalte so, die SQL-Funktion auth_lookup_user_by_username gibt sie als "Role" zurueck. Die Handannotation role: string in AuthLookupUserByUsernameRow war eine zweite Fassung desselben Wertes und faellt damit weg. SessionUser und UploadedPng in bug-reports.service.ts sind jetzt Pick<> der neuen Typen statt eigener Beschreibungen. Fixtures in auth.controller.spec.ts ergaenzt: sie uebergaben einen Aufrufer ohne username und ohne mustChangePassword - eine Form, die JwtStrategy nie erzeugt. Testzahlen unveraendert. noExplicitAny in apps/api/src: 149 -> 137. type-check 4/4, lint 5/5, apps/api 72/1143, apps/web 73/531. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -16,6 +16,7 @@ import { LdapService } from '../ldap/ldap.service';
|
||||
import { MailService } from '../mail/mail.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { forTenant } from '../prisma/prisma-tenant.extension';
|
||||
import type { JwtPayload, LoginUser } from './types/auth-user';
|
||||
|
||||
/**
|
||||
* Zeilenform der drei auth_lookup_*-Datenbankfunktionen
|
||||
@@ -29,7 +30,12 @@ interface AuthLookupUserByUsernameRow {
|
||||
passwordHash: string | null;
|
||||
ldapDn: string | null;
|
||||
isActive: boolean;
|
||||
role: string;
|
||||
/**
|
||||
* Die SQL-Funktion deklariert diese Spalte als `role "Role"` (Migration
|
||||
* 20260909160000, Zeile 64) — `string` war hier eine weitere Fassung
|
||||
* desselben Wertes, nicht seine Beschreibung (quick-260921-m34).
|
||||
*/
|
||||
role: Role;
|
||||
displayName: string | null;
|
||||
mustChangePassword: boolean;
|
||||
}
|
||||
@@ -104,7 +110,10 @@ export class AuthService {
|
||||
* T-02-01: Returns null on any failure (never reveals which field is wrong).
|
||||
* Pitfall 6: Checks isActive to prevent deactivated users from logging in.
|
||||
*/
|
||||
async validateUser(username: string, password: string): Promise<any> {
|
||||
async validateUser(
|
||||
username: string,
|
||||
password: string,
|
||||
): Promise<AuthLookupUserByUsernameRow | null> {
|
||||
// Usernames are stored lowercase (case-insensitive login).
|
||||
const rows = await this.prisma.$queryRaw<AuthLookupUserByUsernameRow[]>`
|
||||
SELECT * FROM auth_lookup_user_by_username(${username.toLowerCase()})
|
||||
@@ -167,8 +176,8 @@ export class AuthService {
|
||||
* D-02: 30-day session.
|
||||
* T-02-02: httpOnly + secure (prod) + sameSite=lax.
|
||||
*/
|
||||
async login(user: any, response: Response) {
|
||||
const payload = {
|
||||
async login(user: LoginUser, response: Response) {
|
||||
const payload: JwtPayload = {
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
@@ -373,7 +382,7 @@ export class AuthService {
|
||||
data: { passwordHash, mustChangePassword: false },
|
||||
});
|
||||
|
||||
const payload = {
|
||||
const payload: JwtPayload = {
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
|
||||
Reference in New Issue
Block a user