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.

Relaterade artiklar