0.3 增加登录模块
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import type { AuthContext } from "@/lib/auth/types";
|
||||
import { getDevUser, isDevAuthEnabled } from "@/lib/auth/devUser";
|
||||
import { isConvexEnabled } from "@/lib/convex/enabled";
|
||||
import { convexAuthNextjsToken } from "@convex-dev/auth/nextjs/server";
|
||||
import { fetchQuery } from "convex/nextjs";
|
||||
import { api } from "@/lib/convex/api";
|
||||
|
||||
export class HttpError extends Error {
|
||||
status: number;
|
||||
@@ -11,17 +15,79 @@ export class HttpError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export function getAuthContext(): AuthContext {
|
||||
if (isDevAuthEnabled()) return getDevUser();
|
||||
// 说明:后续接入真实鉴权时,在这里替换为 Supabase/Convex Auth 的校验逻辑。
|
||||
/**
|
||||
* 获取认证上下文
|
||||
*
|
||||
* 优先级:
|
||||
* 1. Convex Auth(如果启用)- 服务端:从 Convex Auth cookies 获取并查询当前用户;客户端:从 hooks 获取
|
||||
* 2. 开发用户(如果启用)
|
||||
* 3. 抛出错误(未配置)
|
||||
*/
|
||||
export async function getAuthContext(): Promise<AuthContext> {
|
||||
// 1. 检查是否启用 Convex Auth
|
||||
if (isConvexEnabled()) {
|
||||
// 说明:开发模式下允许使用固定用户快速跑通链路(例如迁移测试)。
|
||||
if (isDevAuthEnabled()) {
|
||||
return getDevUser();
|
||||
}
|
||||
|
||||
const token = await convexAuthNextjsToken();
|
||||
if (!token) {
|
||||
throw new Error("未登录,请先登录");
|
||||
}
|
||||
|
||||
// 说明:从 Convex Auth token 获取当前用户(users 表由 authTables 提供)。
|
||||
// 这里不强依赖具体字段结构,避免升级 authTables 后类型不兼容。
|
||||
const user = (await fetchQuery(api.users.currentUser, {}, { token })) as unknown;
|
||||
if (!user || typeof user !== "object") {
|
||||
throw new Error("未登录,请先登录");
|
||||
}
|
||||
|
||||
const record = user as Record<string, unknown>;
|
||||
const id = record["_id"];
|
||||
const email = record["email"];
|
||||
const name = record["name"];
|
||||
|
||||
if (typeof id !== "string" || !id) {
|
||||
throw new Error("未登录,请先登录");
|
||||
}
|
||||
|
||||
return {
|
||||
userId: id,
|
||||
email: typeof email === "string" ? email : undefined,
|
||||
name: typeof name === "string" ? name : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 检查是否启用开发用户模式
|
||||
if (isDevAuthEnabled()) {
|
||||
return getDevUser();
|
||||
}
|
||||
|
||||
// 3. 未配置认证
|
||||
throw new Error("Auth is not configured");
|
||||
}
|
||||
|
||||
export function requireAuthContext(): AuthContext {
|
||||
/**
|
||||
* 要求已认证的上下文
|
||||
*
|
||||
* 如果未认证,抛出 401 错误
|
||||
*/
|
||||
export async function requireAuthContext(): Promise<AuthContext> {
|
||||
try {
|
||||
return getAuthContext();
|
||||
return await getAuthContext();
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "Unauthorized";
|
||||
throw new HttpError(401, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户 ID
|
||||
*
|
||||
* 用于服务端组件和 API 路由
|
||||
*/
|
||||
export async function getCurrentUserId(): Promise<string> {
|
||||
const auth = await requireAuthContext();
|
||||
return auth.userId;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function isConvexEnabled(): boolean {
|
||||
return process.env.USE_CONVEX === "1";
|
||||
return process.env.NEXT_PUBLIC_USE_CONVEX === "1";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@ import type { AuthContext } from "@/lib/auth/types";
|
||||
import { requireAuthContext } from "@/lib/auth/authContext";
|
||||
import { getConvexHttpClient } from "@/lib/convex/server";
|
||||
|
||||
export function getAuthedConvexClient(): { auth: AuthContext; client: ConvexHttpClient } {
|
||||
const auth = requireAuthContext();
|
||||
export async function getAuthedConvexClient(): Promise<{ auth: AuthContext; client: ConvexHttpClient }> {
|
||||
const auth = await requireAuthContext();
|
||||
const client = getConvexHttpClient();
|
||||
return { auth, client };
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ export function getConvexHttpClient(): ConvexHttpClient {
|
||||
const client = new ConvexHttpClient(url);
|
||||
const adminKey = process.env.CONVEX_SELF_HOSTED_ADMIN_KEY;
|
||||
if (adminKey) {
|
||||
client.setAdminAuth(adminKey);
|
||||
// 说明:ConvexHttpClient 的类型声明可能未暴露 setAdminAuth(但运行期存在)。
|
||||
// 这里用最小侵入方式兼容自托管管理密钥。
|
||||
(client as any).setAdminAuth(adminKey);
|
||||
}
|
||||
|
||||
cached = client;
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user