javascript - Type-GraphQL: Tillåt dokumentägare och administratör/moderatoråtkomst med @Authorized() dekoratorn
Detaljer
Jag använder type-graphql och försöker begränsa dataåtkomst eller åtgärder för en specifik grupp användare med @Authorized()-dekoratören och en anpassad auth-kontroll som en vakt. Allt fungerar och åtkomst blockeras/tillåts på ett lämpligt sätt enligt dekoratören.
Problem
Jag vill att ägaren/författaren av dokumentet ska kunna redigera/radera det även om det är markerat med @Authorized(["MODERATOR", "ADMIN"]). Eventuellt kan jag markera det med något som @Authorized(["OWNER", "MODERATOR", "ADMIN"]) om det gör det enklare att implementera.
Så vitt jag vet har jag ingen information om vilken modell/dokument användaren försöker komma åt i autentiseringskontrollen, bara argumenten för mutationen. Med andra ord har jag ID:t för det de vill komma åt men inte vilken modell det tillhör.
Fråga
Finns det något sätt jag kan kontrollera om användaren äger dokumentet i auth-kontrollanten eller måste jag markera det som @Authorized() och kontrollera om användaren äger dokumentet eller är administratör/moderator i varje mutation/fråga?
Kod
index.d.ts
declare module "type-graphql" {
function Authorized(): MethodAndPropDecorator;
function Authorized(roles: AccessLevels[]): MethodAndPropDecorator;
function Authorized(...roles: AccessLevels[]): MethodAndPropDecorator;
}
typer.ts
type AccessLevels = "MODERATOR" | "ADMIN";
authChecker.ts
const authChecker: AuthChecker<{ user: User | null }, AccessLevels> = ({ context }, roles): boolean => {
if (!context.user) {
return false;
}
if (roles.length === 0) {
return true;
}
if (context.user.accessLevel > 0 && roles.includes("MODERATOR")) {
return true;
}
return context.user.accessLevel > 1 && roles.includes("ADMIN");
};
EstablishmentResolver.ts
@Authorized(["MODERATOR", "ADMIN"])
@Mutation(() => EstablishmentType, { description: "Deletes a establishment by ID" })
async deleteEstablishment(@Args() { id }: EstablishmentIdArg): Promise<Establishment> {
const establishment = await Establishment.findOne({ where: { id } });
if (!establishment) {
throw new Error("Establishment does not exist");
}
await establishment.destroy();
return establishment;
}
Svar #1
Försök att ändra signaturen och logiken för att möjliggöra att en callback kan skickas in i dekoratorn, vilket kommer att lösa "ägare"-villkoret:
@ObjectType
class User {
@Authorized({
roles: ["MODERATOR", "ADMIN"],
owner: ({ root, context }) => {
return root.id === context.user.id;
},
})
@Field()
email: string;
}
Var medveten om att du inte alltid kan göra det i authChecker eller middleware eftersom de körs innan din resolver-kod, så i fallet med deleteEstablishment finns det inget universellt sätt att matcha establishmentId med user.id för att avgöra om det är en ägare eller inte.
