I'm using cognito authentication, I create a middlware
const { email } = payload;
req.headers['user-email'] = email as string;
I want to write this kind of function
public async httpCheck(query: any, args: any, context: any,
resolveInfo: any) {
console.log('authhealth');
console.log("context "+ context.userEmail);
console.log("query : "+ query.userEmail);
(context.userEmail === query.userEmail ) ? console.log("authorized successfully") : console.log("authorization failed");
return 'OK';
}
From your example, it looks like you are wanting to reject the whole request if the email from the request header does not match an email being provided as an argument to a field in the GraphQL query.
So given the following query:
query MyQuery($userEmail:String!) {
userByEmail(email: $userEmail) {
id
email
familyName
givenName
}
}
If you want to check that the header email equals the email
argument of userByEmail
BEFORE Postgraphile executes the operation, you need to use a Postgraphile Server Plugin which adds a dynamic validation rule that implements the check:
import type { PostGraphilePlugin } from "postgraphile";
import type { ValidationRule } from "graphql";
import { GraphQLError } from "graphql";
import type { IncomingMessage } from "http";
import type { Plugin } from "graphile-build";
// Defines a graphile plugin that uses a field argument build hook to add
// metadata as an extension to the "email" argument of the "userByEmail" field
const AddEmailMatchPlugin: Plugin = (builder) => {
builder.hook(
"GraphQLObjectType:fields:field:args",
(args, build, context) => {
// access whatever data you need from the field context. The scope contains
// basically any information you might desire including the database metadata
// e.g table name, primary key.
const {
scope: { fieldName, isRootQuery },
} = context;
if (!isRootQuery && fieldName !== "userByEmail") {
return args;
}
if (args.email) {
return {
...args,
email: {
...args.email,
// add an extensions object to the email argument
// this will be accessible from the finalized GraphQLSchema object
extensions: {
// include any existing extension data
...args.email.extensions,
// this can be whatetever you want, but it's best to create
// an object using a consistent key for any
// GraphQL fields/types/args that you modify
myApp: {
matchToUserEmail: true,
},
},
},
};
}
return args;
}
);
};
// define the server plugin
const matchRequestorEmailWithEmailArgPlugin: PostGraphilePlugin = {
// this hook enables the addition of dynamic validation rules
// where we can access the underlying http request
"postgraphile:validationRules": (
rules,
context: { req: IncomingMessage; variables?: Record<string, unknown> }
) => {
const {
variables,
// get your custom user context/jwt/headers from the request object
// this example assumes you've done this in some upstream middleware
req: { reqUser },
} = context;
if (!reqUser) {
throw Error("No user found!");
}
const { email, role } = reqUser;
const vr: ValidationRule = (validationContext) => {
return {
Argument: {
// this fires when an argument node has been found in query AST
enter(node, key) {
if (typeof key === "number") {
// get the schema definition of the argument
const argDef = validationContext.getFieldDef()?.args[key];
if (argDef?.extensions?.myApp?.matchToUserEmail) {
// restrict check to a custom role
if (role === "standard") {
const nodeValueKind = node.value.kind;
let emailsMatch = false;
// basic case
if (nodeValueKind === "StringValue") {
if (node.value.value === email) {
emailsMatch = true;
}
}
// must account for the value being provided by a variable
else if (nodeValueKind === "Variable") {
const varName = node.value.name.value;
if (variables && variables[varName] === email) {
emailsMatch = true;
}
}
if (!emailsMatch) {
validationContext.reportError(
new GraphQLError(
`Field "${
validationContext.getFieldDef()?.name
}" argument "${
argDef.name
}" must match your user email.`,
node
)
);
}
}
}
}
},
},
};
};
return [...rules, vr];
},
// This hook appends the AddEmailMatchPlugin graphile plugin that
// this server plugin depends on for its custom extension.
"postgraphile:options": (options) => {
return {
...options,
appendPlugins: [...(options.appendPlugins || []), AddEmailMatchPlugin],
};
},
};
export default matchRequestorEmailWithEmailArgPlugin;
Then you need to register the server plugin in the Postgraphile middleware options:
const pluginHook = makePluginHook([MatchRequestorEmailWithEmailArgPlugin]);
const postGraphileMiddleware = postgraphile(databaseUrl, "my_schema", {
pluginHook,
// ...
});
If you just want to reject the userByEmail
field in the query and don't care about rejecting before any resolution of any other parts of the request occur, you can use the makeWrapResolversPlugin to wrap the resolver and do the check there.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.