본문 바로가기
버전: 11.x

권한 부여

비공식 베타 번역

이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →

createContext 함수는 들어오는 각 요청에 대해 호출되므로, 여기에서 요청 객체를 통해 호출 사용자에 대한 컨텍스트 정보를 추가할 수 있습니다.

요청 헤더로부터 컨텍스트 생성

server/context.ts
ts
import * as trpcNext from '@trpc/server/adapters/next';
import { decodeAndVerifyJwtToken } from './somewhere/in/your/app/utils';
export async function createContext({
req,
res,
}: trpcNext.CreateNextContextOptions) {
// Create your context based on the request object
// Will be available as `ctx` in all your resolvers
// This is just an example of something you might want to do in your ctx fn
async function getUserFromHeader() {
if (req.headers.authorization) {
const user = await decodeAndVerifyJwtToken(
req.headers.authorization.split(' ')[1],
);
return user;
}
return null;
}
const user = await getUserFromHeader();
return {
user,
};
}
export type Context = Awaited<ReturnType<typeof createContext>>;
server/context.ts
ts
import * as trpcNext from '@trpc/server/adapters/next';
import { decodeAndVerifyJwtToken } from './somewhere/in/your/app/utils';
export async function createContext({
req,
res,
}: trpcNext.CreateNextContextOptions) {
// Create your context based on the request object
// Will be available as `ctx` in all your resolvers
// This is just an example of something you might want to do in your ctx fn
async function getUserFromHeader() {
if (req.headers.authorization) {
const user = await decodeAndVerifyJwtToken(
req.headers.authorization.split(' ')[1],
);
return user;
}
return null;
}
const user = await getUserFromHeader();
return {
user,
};
}
export type Context = Awaited<ReturnType<typeof createContext>>;

옵션 1: 리졸버를 사용한 권한 부여

server/routers/_app.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
import type { Context } from '../context';
export const t = initTRPC.context<Context>().create();
const appRouter = t.router({
// open for anyone
hello: t.procedure
.input(z.string().nullish())
.query((opts) => `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`),
// checked in resolver
secret: t.procedure.query((opts) => {
if (!opts.ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return {
secret: 'sauce',
};
}),
});
server/routers/_app.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
import type { Context } from '../context';
export const t = initTRPC.context<Context>().create();
const appRouter = t.router({
// open for anyone
hello: t.procedure
.input(z.string().nullish())
.query((opts) => `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`),
// checked in resolver
secret: t.procedure.query((opts) => {
if (!opts.ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return {
secret: 'sauce',
};
}),
});

옵션 2: 미들웨어를 사용한 권한 부여

server/routers/_app.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
import type { Context } from '../context';
export const t = initTRPC.context<Context>().create();
// you can reuse this for any procedure
export const protectedProcedure = t.procedure.use(
async function isAuthed(opts) {
const { ctx } = opts;
// `ctx.user` is nullable
if (!ctx.user) {
// ^?
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return opts.next({
ctx: {
// ✅ user value is known to be non-null now
user: ctx.user,
// ^?
},
});
},
);
t.router({
// this is accessible for everyone
hello: t.procedure
.input(z.string().nullish())
.query((opts) => `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`),
admin: t.router({
// this is accessible only to admins
secret: protectedProcedure.query((opts) => {
return {
secret: 'sauce',
};
}),
}),
});
server/routers/_app.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
import type { Context } from '../context';
export const t = initTRPC.context<Context>().create();
// you can reuse this for any procedure
export const protectedProcedure = t.procedure.use(
async function isAuthed(opts) {
const { ctx } = opts;
// `ctx.user` is nullable
if (!ctx.user) {
// ^?
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return opts.next({
ctx: {
// ✅ user value is known to be non-null now
user: ctx.user,
// ^?
},
});
},
);
t.router({
// this is accessible for everyone
hello: t.procedure
.input(z.string().nullish())
.query((opts) => `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`),
admin: t.router({
// this is accessible only to admins
secret: protectedProcedure.query((opts) => {
return {
secret: 'sauce',
};
}),
}),
});