72 lines
1.6 KiB
TypeScript
Executable File
72 lines
1.6 KiB
TypeScript
Executable File
import { initTRPC } from '@trpc/server';
|
||
import superjson from 'superjson';
|
||
import { sessionManager } from '../auth/session';
|
||
import { UserWithRelations } from '@fenghuo/common/user';
|
||
import { extractRequestInfo, RequestInfo } from '../utils/request';
|
||
|
||
// 定义上下文类型
|
||
export interface Context {
|
||
user?: UserWithRelations;
|
||
requestInfo: RequestInfo;
|
||
}
|
||
|
||
/**
|
||
* 创建上下文函数(用于tRPC服务器)
|
||
* @param opts 选项对象,包含请求对象
|
||
* @returns 上下文对象
|
||
*/
|
||
export const createContext = async (opts?: { req?: any }): Promise<Context> => {
|
||
// 提取请求信息(IP地址、User Agent等)
|
||
const requestInfo = extractRequestInfo(opts?.req);
|
||
|
||
// 如果有请求对象,尝试获取用户会话信息
|
||
if (opts?.req) {
|
||
const session = await sessionManager.getSessionFromRequest(opts.req);
|
||
if (session) {
|
||
return {
|
||
user: session.user,
|
||
requestInfo
|
||
};
|
||
}
|
||
}
|
||
|
||
// 没有有效的认证信息时返回空上下文
|
||
return {
|
||
user: undefined,
|
||
requestInfo
|
||
};
|
||
};
|
||
|
||
// 初始化 tRPC
|
||
const t = initTRPC.context<Context>().create({
|
||
transformer: superjson,
|
||
errorFormatter({ shape, error }) {
|
||
return {
|
||
...shape,
|
||
data: {
|
||
...shape.data,
|
||
code: error.code,
|
||
},
|
||
};
|
||
},
|
||
});
|
||
|
||
export const publicProcedure = t.procedure;
|
||
export const router = t.router;
|
||
|
||
/**
|
||
* 需要认证的过程 - 确保用户已登录
|
||
*/
|
||
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
|
||
// 检查用户是否已通过认证
|
||
if (!ctx.user) {
|
||
throw new Error('未授权访问 - 请先登录');
|
||
}
|
||
|
||
return next({
|
||
ctx: {
|
||
...ctx,
|
||
user: ctx.user, // 确保用户存在,用户信息可通过 ctx.user 访问
|
||
},
|
||
});
|
||
}); |