You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于GraphQL与Serverless的微服务架构授权方案咨询

Optimal Gateway-Level Authorization for Your GraphQL + Serverless Architecture

Great question! Given your setup—isolated Serverless services per DynamoDB table, schema stitching via graphql-tools at API Gateway, and a custom authorizer already injecting the userId into the GraphQL context—here’s a clean, modular approach to implement authorization at the gateway layer while keeping your downstream services completely focused on business logic:

1. Build Custom Authorization Directives

GraphQL directives are perfect for declarative, modular authorization. Define reusable directives at the gateway layer to mark which operations/fields need authorization checks, then wire up logic to enforce them during schema stitching.

For example, create directives like:

  • @requiresAuth: Ensures the user is authenticated (i.e., userId exists in the context)
  • @requiresOwnership(resourceField: String!): Ensures the authenticated user owns the target resource (matches userId to a field on the resource)

Here’s a snippet of how to define these in your gateway schema:

directive @requiresAuth on QUERY | MUTATION | FIELD_DEFINITION
directive @requiresOwnership(resourceField: String!) on QUERY | MUTATION | FIELD_DEFINITION

2. Centralize Authorization Logic in Reusable Utilities

Create a dedicated authorization utility file at the gateway layer to house all your permission-checking logic. This keeps your code DRY and makes it easy to update rules without touching downstream services.

Example utility functions:

// gateway/utils/authorization.js
export const isAuthenticated = (context) => {
  return !!context.userId;
};

export const ownsResource = async (context, resourceId, resourceField = 'userId') => {
  // Fetch the resource from the appropriate downstream service (or cache if possible)
  const resource = await fetchResourceById(resourceId);
  return resource[resourceField] === context.userId;
};

3. Use Directive Transformers to Enforce Rules During Schema Stitching

Leverage graphql-tools’ transformer capabilities to wrap resolvers of fields/operations marked with your authorization directives. This happens at the gateway level, so downstream resolvers never even see the authorization logic.

Here’s how to wire this up:

// gateway/schema-stitching.js
import { stitchSchemas, wrapResolver } from '@graphql-tools/stitch';
import { isAuthenticated, ownsResource } from './utils/authorization';

const authDirectiveTransformer = (schema) => {
  return schema.transform({
    resolver: (resolverConfig, fieldName, typeName) => {
      const fieldDirectives = resolverConfig.astNode?.directives;
      
      // Check for @requiresAuth
      const requiresAuth = fieldDirectives?.some(d => d.name.value === 'requiresAuth');
      if (requiresAuth) {
        resolverConfig.resolve = wrapResolver(resolverConfig.resolve, async (args, context, info) => {
          if (!isAuthenticated(context)) {
            throw new Error('Unauthorized: You must be logged in');
          }
          return resolverConfig.resolve(args, context, info);
        });
      }

      // Check for @requiresOwnership
      const ownershipDirective = fieldDirectives?.find(d => d.name.value === 'requiresOwnership');
      if (ownershipDirective) {
        const resourceField = ownershipDirective.arguments?.find(a => a.name.value === 'resourceField').value.value;
        resolverConfig.resolve = wrapResolver(resolverConfig.resolve, async (args, context, info) => {
          if (!isAuthenticated(context)) {
            throw new Error('Unauthorized: You must be logged in');
          }
          const resourceId = args.id; // Adjust based on your argument naming
          const hasOwnership = await ownsResource(context, resourceId, resourceField);
          if (!hasOwnership) {
            throw new Error('Unauthorized: You do not own this resource');
          }
          return resolverConfig.resolve(args, context, info);
        });
      }

      return resolverConfig;
    }
  });
};

// Apply the transformer when stitching schemas
const stitchedSchema = stitchSchemas({
  subschemas: [/* your downstream service schemas */],
  transforms: [authDirectiveTransformer]
});

4. Enforce Granular Permissions Per Operation/Field

Mark your stitched schema operations with the directives to enforce granular rules. For example:

type Query {
  getPrivateUserProfile(userId: ID!): User @requiresAuth
  getPost(postId: ID!): Post @requiresOwnership(resourceField: "authorId")
}

type Mutation {
  updateUserProfile(input: UpdateProfileInput!): User @requiresAuth
  deletePost(postId: ID!): Post @requiresOwnership(resourceField: "authorId")
}

Key Benefits of This Approach

  • Downstream Service Purity: Your table-specific Serverless services only handle data access and business logic—no authorization code cluttering them up.
  • Modular & Maintainable: All authorization rules live in one place at the gateway, making it easy to update or add new permissions.
  • Declarative & Clear: Directives make authorization requirements explicit in your schema, which is great for documentation and developer clarity.
  • Scalable: As you add more downstream services, you just apply the same directives to new operations without rewriting authorization logic.

内容的提问来源于stack exchange,提问作者MikeyCarlstein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:03:22