を使用して階層的なアクセスをモデル化する方法


私は米国のクライアントと医療の管理を管理するためのそのようなアプリの最初の構築に取り組んでいる.それはHIPAAコンプライアンスの下にあります、そして、我々がユーザーデータへの無許可のアクセスを許しないことは、重要です.
アプリの一部として、私たちはクライアントの会社からの管理スタッフだけでなく、その顧客によって使用される管理ツールを構築している.基本的に、管理ツールには三つのロールがあります.

  • 管理者:これらはクライアントの会社からの管理スタッフです.ユーザーのこのグループは、新しいテナントを追加するなど、すべての機能にアクセスできます.

  • テナント:これらは典型的な健康情報交換(HIES)であるクライアントの顧客からの管理スタッフです.HIEは、それらの間のデータ交換を促進するために複数のヘルスケアプロバイダー(例えば病院、薬局)と協力します.HIEの管理スタッフは、したがって、それが協力するどんなヘルスケアプロバイダーと同様に彼ら自身の組織に関連した情報へのアクセスもするべきです.

  • サービスエリア:これらは上記のHIESと協力するヘルスケアプロバイダーからの管理スタッフです.彼らは患者だけでなく、自分の組織に関する情報へのアクセスを持っている.
  • これは関与している実体の徹底的な単純化です、しかし、それは我々がモデル化する必要があるアクセスの異なるタイを説明するのに役立ちます:
  • Admin ユーザーはすべてにアクセスできます.
  • Tenant ユーザーは自分のデータにアクセスすることができますが、その副サービスエリアに属するデータに加えて.
  • Service Area ユーザーは自分のデータのみにアクセスできます.

  • 良いニュースは、AppSyncは簡単にグループベースの認証を実装することを認識することです.はone of the reasons このプロジェクトのAPIゲートウェイでAppSyncと一緒に行くことを決めた理由.
    しかしながら、GraphSQLスキーマにおけるこれらの重複した動作をモデリングすることは、まだ大きな課題であった.

    問題


    問題の根本は、各グループが実行できる重複するアクションが多いことです.
    例えば、Admin ユーザーは、新しいサービス領域を追加し、任意のTenant . エーTenant ユーザーはまた、新しいサービス領域を追加することができますが、サービスエリアを誰もが自分自身を関連付けることはできません.
    そのように、我々は異なる入力で2つの別々の突然変異を必要として、異なる認知グループへの彼らの接近をロックダウンします.下記からご覧いただけますTenant ユーザーは、私はaddServiceAreaAsTenant iを越えることができない突然変異tenantId サービスエリアが関連付けられています.
    type Mutation {
      addServiceAreaAsAdmin(tenantId: ID!, name: String!): ServiceArea!
      @aws_auth(cognito_groups: ["Admin"])
    
      addServiceAreaAsTenant(name: String!): ServiceArea!
      @aws_auth(cognito_groups: ["Tenant"])
    }
    
    我々はより多くのクエリや突然変異を追加すると、これはすぐに厄介になります.
    のための重複がたくさんあります@aws_auth(cognito_groups: …) 節は、ユーザーの各グループが行うことができます一目で見るのは簡単ではない.また、それらを区別するために、これらのクエリや突然変異の名前について、ますます創造的になる必要があります.
    コピーと貼り付けのエラーを簡単にクリープすることができます(ほとんどは)、それはまた、フロントエンドの開発者のためのクエリとは、ユーザーのために使用する必要があります突然変異の追跡を混乱させる.
    schema {
      query: Query
      mutation: Mutation
    }
    
    type Query {
      getTenantById(id: ID!): Tenant!
      @aws_auth(cognito_groups: ["Admin"])
    
      getServiceAreaById(id: ID!): ServiceArea!
      @aws_auth(cognito_groups: ["Admin"])
    
      getMyProfileAsTenant: Tenant!
      @aws_auth(cognito_groups: ["Tenant"])
    
      getMyServiceArea(id: ID!): ServiceArea!
      @aws_auth(cognito_groups: ["Tenant"])
    
      getMyProfileAsServiceArea: ServiceArea!
      @aws_auth(cognito_groups: ["ServiceArea"])
    }
    
    type Mutation {
      addTenant(name: String!): Tenant!
      @aws_auth(cognito_groups: ["Admin"])
    
      addServiceAreaAsAdmin(tenantId: ID!, name: String!): ServiceArea!
      @aws_auth(cognito_groups: ["Admin"])
    
      updateMyProfileAsTenant(name: String!): Tenant!
      @aws_auth(cognito_groups: ["Tenant"])
    
      addServiceAreaAsTenant(name: String!): ServiceArea!
      @aws_auth(cognito_groups: ["Tenant"])
    
      updateMyProfileAsServiceArea(name: String!): ServiceArea!
      @aws_auth(cognito_groups: ["ServiceArea"])
    }
    
    type Tenant {
      id: ID!
      name: String!
    }
    
    type ServiceArea {
      id: ID!
      name: String!
      tenantId: ID!
    }
    

    ネストした問い合わせ/突然変異型の使用


    このプロジェクトの複雑さをより簡単にするために、我々はそれぞれのグループをカプセル化することを決めたQuery and Mutation 種類
    下記のように、ユーザーの各グループは、独自の取得Query and Mutation 種類アクセスは、単一の場所で制御され、それはすべてのユーザーのグループを一目で行うことができますを参照してくださいに簡単です.また、我々はもう重複アクション上の命名規則に依存する必要はありません.
    schema { 
      query: Query
      mutation: Mutation
    }
    
    type Query {
      asAdmin: AdminQuery
      @aws_auth(cognito_groups: ["Admin"])
    
      asTenant: TenantQuery
      @aws_auth(cognito_groups: ["Tenant"])
    
      asServiceArea: ServiceAreaQuery
      @aws_auth(cognito_groups: ["ServiceArea"])
    }
    
    type Mutation {
      asAdmin: AdminMutation
      @aws_auth(cognito_groups: ["Admin"])
    
      asTenant: TenantMutation
      @aws_auth(cognito_groups: ["Tenant"])
    
      asServiceArea: ServiceAreaMutation
      @aws_auth(cognito_groups: ["ServiceArea"])
    }
    
    type AdminQuery {
      getTenant(id: ID!): Tenant!
      getServiceArea(id: ID!): ServiceArea!
    }
    
    type TenantQuery {
      getMyProfile: Tenant!
      getMyServiceArea(id: ID!): ServiceArea!
    }
    
    type ServiceAreaQuery {
      getMyProfile: ServiceArea!
    }
    
    type AdminMutation {
      addTenant(name: String!): Tenant!
      addServiceArea(tenantId: ID!, name: String!): ServiceArea!
    }
    
    type TenantMutation {
      updateMyProfile(name: String!): Tenant!
      addServiceArea(name: String!): ServiceArea!
    }
    
    type ServiceAreaMutation {
      updateMyProfile(name: String!): ServiceArea!
    }
    
    type Tenant {
      id: ID!
      name: String!
    }
    
    type ServiceArea {
      id: ID!
      name: String!
      tenantId: ID!
    }
    
    これにより、既存のセキュリティモデルを壊すことなく、プロジェクトが成長し続けるにつれて、GraphSQLスキーマを維持しやすくなります.
    としてAdmin ユーザーは、クエリと突然変異をAdminQuery and AdminMutation 種類


    としてTenant ユーザ名tenantId 私の組織のカスタム属性として私の認知ユーザーにキャプチャされます.

    Aのための質問と突然変異Tenant ユーザは決して受け入れないtenantId 引数として、常に$context.identity . これは、テナントがカスタム検証ロジックを使用してコードを捨てる必要がなく、テナントが独自のデータにアクセスすることができます.
    そして私はそれに属していないのでAdmin グループ、私はそのクエリと突然変異にアクセスする権限はありません.

    しかし、私は私自身のデータだけでなく、私の組織に関連付けられているサービスエリアのアクセスデータを行動することができます.


    そして同じService Area ユーザーのアクセスは、自身のデータに制限されます.
    これに加えて、HIPAAコンプライアンスも、ユーザーがアクセスしたデータの監査証跡を持つ必要があります.それで、我々は完全に要求応答ログを実装しなければなりませんでした.我々は、後のポストでこの特定の話題に飛び込みます.
    一方、あなたがこの階層モデルがどのようにあなた自身のために働くかを見たいならばthis repo そしてそれを試してください.
    あなたが手でGraphSQLとAppSyncを学びたいならば、チュートリアルでそれから私をチェックしてくださいnew AppSync course ここでは、AppSync、ラムダ、ダイナモ、認知とVueの組み合わせを使用してTwitterのクローンを構築します.jsあなたは別のGraphSQLのモデリング技術については、どのようにレゾルバ、CI/CD、監視、警告をデバッグし、はるかにデバッグします.

    郵便How to model hierarchical access with AppSync 最初に現れたtheburningmonk.com .