给所有请求都加上jwt,隐藏生成jwt的secret(放到.env中),隐藏app-secret(放在pm2运行配置文件中,后续直接读取环境配置即可)

This commit is contained in:
2025-10-17 15:28:22 +08:00
parent 9ec6d30573
commit 59706b70d0
70 changed files with 2279 additions and 688 deletions
+111
View File
@@ -0,0 +1,111 @@
// app/api/db-client.server.ts
import { getUserSession } from '~/api/login/auth.server';
import { runWithContext } from './postgrest-client';
/**
* 在认证上下文中运行
*
* 所有在此上下文中调用的 postgrest 函数(postgrestGet/Post/Put/Delete
* 都会自动获取并添加 JWT Token 到 Authorization 头部
*
* @param request Remix Request 对象
* @param fn 要在认证上下文中执行的函数
* @returns 函数执行结果
* @throws 如果用户未登录则抛出错误
*
* @example
* ```typescript
* export async function loader({ request }: LoaderFunctionArgs) {
* return await runInAuthContext(request, async () => {
* // 所有 postgrest 调用自动带 JWT
* const users = await postgrestGet('users', { limit: 10 });
* const docs = await postgrestGet('documents', { filter: { status: 'eq.0' } });
*
* return json({ users: users.data, docs: docs.data });
* });
* }
* ```
*/
export async function runInAuthContext<T>(
request: Request,
fn: () => T | Promise<T>
): Promise<T> {
const { frontendJWT, isAuthenticated } = await getUserSession(request);
if (!isAuthenticated || !frontendJWT) {
throw new Error('用户未登录,无法执行需要认证的操作');
}
// 在上下文中设置 JWT,所有 postgrest 调用都会自动使用
return runWithContext({ jwt: frontendJWT }, fn);
}
/**
* 在公开上下文中运行(不需要认证)
*
* 用于公开数据访问,不会添加 JWT Token
*
* @param fn 要执行的函数
* @returns 函数执行结果
*
* @example
* ```typescript
* export async function loader() {
* return runInPublicContext(async () => {
* const articles = await postgrestGet('public_articles', {
* filter: { published: 'eq.true' }
* });
* return json({ articles: articles.data });
* });
* }
* ```
*/
export function runInPublicContext<T>(
fn: () => T | Promise<T>
): T | Promise<T> {
// 在空上下文中运行,不设置 JWT
return runWithContext({}, fn);
}
/**
* 在可选认证上下文中运行
*
* 如果用户已登录,会自动添加 JWT;
* 如果用户未登录,则不添加 JWT(不会抛出错误)
*
* @param request Remix Request 对象
* @param fn 要执行的函数
* @returns 函数执行结果
*
* @example
* ```typescript
* export async function loader({ request }: LoaderFunctionArgs) {
* return await runInOptionalAuthContext(request, async () => {
* // 如果用户登录,会带 JWT(可能看到更多内容)
* // 如果用户未登录,不带 JWT(看到基础内容)
* const content = await postgrestGet('content', { limit: 20 });
* return json({ content: content.data });
* });
* }
* ```
*/
export async function runInOptionalAuthContext<T>(
request: Request,
fn: () => T | Promise<T>
): Promise<T> {
try {
const { frontendJWT, isAuthenticated } = await getUserSession(request);
if (isAuthenticated && frontendJWT) {
// 用户已登录,使用 JWT
return runWithContext({ jwt: frontendJWT }, fn);
}
} catch (error) {
// 获取会话失败,继续以公开方式运行
console.warn('获取用户会话失败,以公开方式运行:', error);
}
// 用户未登录或获取会话失败,以公开方式运行
return runWithContext({}, fn);
}