Fix new-home login reliability and set modal backdrop to 85%
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-14 02:15:03 +08:00
parent 5933d57246
commit aa98663ce8
6 changed files with 28 additions and 16 deletions

View File

@ -44,9 +44,10 @@ export const login = async (
email: formData.get("email"), email: formData.get("email"),
password: formData.get("password"), password: formData.get("password"),
}); });
const normalizedEmail = validatedData.email.trim().toLowerCase();
await signIn("credentials", { await signIn("credentials", {
email: validatedData.email, email: normalizedEmail,
password: validatedData.password, password: validatedData.password,
redirect: false, redirect: false,
}); });
@ -86,15 +87,16 @@ export const register = async (
email: formData.get("email"), email: formData.get("email"),
password: formData.get("password"), password: formData.get("password"),
}); });
const normalizedEmail = validatedData.email.trim().toLowerCase();
const [user] = await getUser(validatedData.email); const [user] = await getUser(normalizedEmail);
if (user) { if (user) {
return { status: "user_exists" } as RegisterActionState; return { status: "user_exists" } as RegisterActionState;
} }
await createUser(validatedData.email, validatedData.password); await createUser(normalizedEmail, validatedData.password);
await signIn("credentials", { await signIn("credentials", {
email: validatedData.email, email: normalizedEmail,
password: validatedData.password, password: validatedData.password,
redirect: false, redirect: false,
}); });

View File

@ -1,13 +1,10 @@
import type { NextAuthConfig } from "next-auth"; import type { NextAuthConfig } from "next-auth";
import { isIP } from "node:net";
export function buildAuthConfig(authUrl?: string | null): NextAuthConfig { export function buildAuthConfig(authUrl?: string | null): NextAuthConfig {
const resolvedAuthUrl = authUrl || process.env.AUTH_URL || ""; const resolvedAuthUrl = authUrl || process.env.AUTH_URL || "";
const isSecure = resolvedAuthUrl.startsWith("https://"); const isSecure = resolvedAuthUrl.startsWith("https://");
const hostName = resolvedAuthUrl ? new URL(resolvedAuthUrl).hostname : undefined; // Use host-only cookies to avoid cross-domain login issues in multi-domain deployments.
// Browsers may reject `Domain` cookies for IP hosts; keep them host-only in that case. const cookieDomain = undefined;
const cookieDomain =
hostName && hostName !== "localhost" && isIP(hostName) === 0 ? hostName : undefined;
return { return {
trustHost: true, trustHost: true,

View File

@ -115,7 +115,14 @@ function createBaseProviders(googleClientId?: string, googleClientSecret?: strin
} }
// 2. 邮箱密码登录逻辑 // 2. 邮箱密码登录逻辑
const { email, password } = credentials; const email = String(credentials?.email || "").trim().toLowerCase();
const password = String(credentials?.password || "");
if (!email || !password) {
await compare(password || "", DUMMY_PASSWORD);
return null;
}
const users = await getUser(email); const users = await getUser(email);
if (users.length === 0) { if (users.length === 0) {

View File

@ -548,7 +548,7 @@ export default function Page() {
{/* 钉钉登录 iframe 弹窗 / 多组织选择 */} {/* 钉钉登录 iframe 弹窗 / 多组织选择 */}
{showDingTalkModal && ( {showDingTalkModal && (
<div <div
className="fixed inset-0 bg-black/95 flex items-center justify-center z-50 backdrop-blur-sm" className="fixed inset-0 bg-black/85 flex items-center justify-center z-50 backdrop-blur-sm"
onClick={(e) => { onClick={(e) => {
if (e.target === e.currentTarget) closeDingTalkModal(); if (e.target === e.currentTarget) closeDingTalkModal();
}} }}

View File

@ -594,7 +594,7 @@ export function LovartHome({
}; };
const handleEmailLogin = async () => { const handleEmailLogin = async () => {
const email = loginEmail.trim(); const email = loginEmail.trim().toLowerCase();
if (!email || !loginPassword) { if (!email || !loginPassword) {
toast.error("请输入邮箱和密码"); toast.error("请输入邮箱和密码");
return; return;
@ -608,7 +608,7 @@ export function LovartHome({
redirect: false, redirect: false,
}); });
if (result?.error) { if (!result || result.error || result.ok === false) {
toast.error("登录失败,请检查账号密码"); toast.error("登录失败,请检查账号密码");
return; return;
} }
@ -1235,7 +1235,7 @@ export function LovartHome({
{loginDialogOpen ? ( {loginDialogOpen ? (
<div <div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/95 p-4 backdrop-blur-[1px]" className="fixed inset-0 z-50 flex items-center justify-center bg-black/85 p-4 backdrop-blur-[1px]"
onClick={() => setLoginDialogOpen(false)} onClick={() => setLoginDialogOpen(false)}
> >
<div <div

View File

@ -65,11 +65,16 @@ import { db } from "@/lib/db";
export async function getUser(email: string): Promise<User[]> { export async function getUser(email: string): Promise<User[]> {
const normalizedEmail = email.trim().toLowerCase();
if (!normalizedEmail) {
return [];
}
try { try {
return await db return await db
.select() .select()
.from(user) .from(user)
.where(eq(user.email, email)) .where(sql`lower(${user.email}) = ${normalizedEmail}`)
.orderBy(desc(user.createdAt)); .orderBy(desc(user.createdAt));
} catch (_error) { } catch (_error) {
throw new ChatSDKError( throw new ChatSDKError(
@ -81,9 +86,10 @@ export async function getUser(email: string): Promise<User[]> {
export async function createUser(email: string, password: string) { export async function createUser(email: string, password: string) {
const hashedPassword = generateHashedPassword(password); const hashedPassword = generateHashedPassword(password);
const normalizedEmail = email.trim().toLowerCase();
try { try {
return await db.insert(user).values({ email, password: hashedPassword }); return await db.insert(user).values({ email: normalizedEmail, password: hashedPassword });
} catch (_error) { } catch (_error) {
throw new ChatSDKError("bad_request:database", "Failed to create user"); throw new ChatSDKError("bad_request:database", "Failed to create user");
} }