File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
'use server';
import { redirect } from 'next/navigation';
import { revalidatePath } from 'next/cache';
import { requestAdminLogin } from '@/lib/data/repositories/auth-repository';
import { createSession } from '@/lib/auth/session';
export type LoginFormState = {
error?: string;
};
const GENERIC_LOGIN_ERROR = '아이디 또는 비밀번호가 올바르지 않습니다.';
const MAX_LOGIN_ID_LENGTH = 100;
const MAX_PASSWORD_LENGTH = 200;
function readTrimmedField(formData: FormData, key: string): string | null {
const value = formData.get(key);
if (typeof value !== 'string') {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
/**
* 로그인 Server Action — 인증의 진입점이라 사전 인증 확인은 성립하지 않는다(예외로 명시).
* 입력 검증 → 자격 검증 → 실패 시 계정 존재 여부를 드러내지 않는 일반화 메시지 →
* 성공 시 세션 생성 → 클라이언트 라우터 캐시 무효화 → 리다이렉트.
*/
export async function login(
_prevState: LoginFormState,
formData: FormData
): Promise<LoginFormState> {
const loginId = readTrimmedField(formData, 'loginId');
const password = readTrimmedField(formData, 'password');
if (
!loginId ||
!password ||
loginId.length > MAX_LOGIN_ID_LENGTH ||
password.length > MAX_PASSWORD_LENGTH
) {
return { error: GENERIC_LOGIN_ERROR };
}
const result = await requestAdminLogin({ loginId, password });
if (!result) {
return { error: GENERIC_LOGIN_ERROR };
}
await createSession({
adminId: result.admin.id,
loginId: result.admin.loginId,
admRoleCd: result.admin.roleCode,
accessToken: result.accessToken,
refreshToken: result.refreshToken,
exp: result.accessTokenExpiresAt,
});
revalidatePath('/', 'layout');
redirect('/');
}