在 Amplify 中使用 GraphQL 和 Cognito 认证

总结

这是关于首次 Amplify 部署的续篇。
在前一次项目创建时,我们设置了使用 Cognito 进行身份验证,并将必要的配置放入了 Docker 中的模拟环境。
现在我们将实现使用 Cognito 进行用户身份验证,并与 GraphQL 进行协作。

添加用户认证功能。

yarn add aws-amplify aws-amplify-react

为了在创建帐户时不需要电话号码,我们在 withAuthenticator 的 signUpConfig 中添加了 hiddenDefaults。

import React from 'react';
import Amplify from '@aws-amplify/core';
import awsmobile from './aws-exports';
import { withAuthenticator } from 'aws-amplify-react';
import '@aws-amplify/ui/dist/style.css';

Amplify.configure(awsmobile)

const App: React.FC = () => {
  return (
    <>
      <h1>タイトル</h1>
    </>
  )
}

//@ts-ignore
export default withAuthenticator(App, {
  signUpConfig: {
    hiddenDefaults: ['phone_number']
  }
});
スクリーンショット 2020-07-05 10.34.19.png

在登录页面上通过点击创建账户按钮来注册账户,并完成邮件验证后即可登录。会显示”标题”。

创建 GraphQL API

首先,让我们尝试一下自动生成的 schema.graphql 中的 TODO 模型。

type Todo @model {
  id: ID!
  name: String!
  description: String
}

使用 Mock 可以在本地进行验证。

$ amplify mock api
スクリーンショット 2020-07-05 10.53.48.png
スクリーンショット 2020-07-05 10.55.59.png
スクリーンショット 2020-07-05 10.57.37.png

React 和 GraphQL 的整合

我将展示生成的数据在屏幕上。

由于这次是在 Docker 中进行开发,所以需要将 aws-exports.js 文件中的 aws_appsync_graphqlEndpoint 改为 localhost(仅限本地开发时)。

"aws_appsync_graphqlEndpoint": "http://localhost:20002/graphql",

将App.tsx进行如下更改:
显示保存在Todo中的一项数据。

import React, {useState} from 'react'
import Amplify from '@aws-amplify/core'
import awsmobile from './aws-exports'
import {withAuthenticator} from 'aws-amplify-react'
import '@aws-amplify/ui/dist/style.css'
import {listTodos} from './graphql/queries'
import API, {graphqlOperation} from '@aws-amplify/api'
import { Auth } from 'aws-amplify';

Amplify.configure(awsmobile)

const App: React.FC = () => {
  const [todos, setTodos] = useState<any>({})

  const getTodo = async() => {
    try {
      const res: any = await API.graphql(graphqlOperation(listTodos))
      console.log(res)
      setTodos(res.data.listTodos.items)
    } catch (e) {
      console.log(e)
    }
  }

  const ShowTodo = () => {
    if (todos.length > 0) {
      const todo = todos[0]
      return (
        <>
          <p>{ todo.id }</p>
          <p>{ todo.name }</p>
          <p>{ todo.description }</p>
          <p>{ todo.createdAt }</p>
          <p>{ todo.updatedAt }</p>
        </>
      )
    }
    return (
      <></>
    )
  }

  return (
    <>
      <h1>Todos</h1>
      <button onClick={() => getTodo()}>get todos!</button>
      <div>
        <ShowTodo/>
      </div>
    </>
  )
}
...
スクリーンショット 2020-07-05 15.17.03.png

由Cognito团队进行管理

スクリーンショット 2020-07-05 15.30.45.png

将 schema.graphql 进行如下修改。

type Todo
  @model
  @auth(rules: [
    { allow: owner },
    { allow: groups, groups: ["admin"], operations: [read, update] }
  ])
{
    id: ID!
    name: String!
    description: String
}

通过这样做,成员权限的帐户将无法对Todo进行任何操作。
为了登出一次,我们需要将App.tsx修改如下。

import React, {useState} from 'react'
import Amplify from '@aws-amplify/core'
import awsmobile from './aws-exports'
import {withAuthenticator} from 'aws-amplify-react'
import '@aws-amplify/ui/dist/style.css'
import {listTodos} from './graphql/queries'
import API, {graphqlOperation} from '@aws-amplify/api'
import { Auth } from 'aws-amplify';

Amplify.configure(awsmobile)

const App: React.FC = () => {
  const [todos, setTodos] = useState<any>({})

  const signOut = () => {
    Auth.signOut()
  }

  const getTodo = async() => {
    try {
      const res: any = await API.graphql(graphqlOperation(listTodos))
      console.log(res)
      setTodos(res.data.listTodos.items)
    } catch (e) {
      console.log(e)
    }
  }

  const ShowTodo = () => {
    if (todos.length > 0) {
      const todo = todos[0]
      return (
        <>
          <p>{ todo.id }</p>
          <p>{ todo.name }</p>
          <p>{ todo.description }</p>
          <p>{ todo.createdAt }</p>
          <p>{ todo.updatedAt }</p>
        </>
      )
    }
    return (
      <></>
    )
  }

  return (
    <>
      <button onClick={ () => signOut() }>ログアウト</button>
      <h1>Todos</h1>
      <button onClick={() => getTodo()}>get todos!</button>
      <div>
        <ShowTodo/>
      </div>
    </>
  )
}
...
スクリーンショット 2020-07-05 20.09.15.png

此外,我还希望将屏幕显示按组进行分组,因此我在App.tsx中添加了以下内容。
在首次登录时,获取登录用户的组信息,并根据该信息进行显示分组。
在useEffect中,仅在第一次获取用户信息(如果不将[]作为第二个参数,则会导致无限循环)。

  const [group, updateGroup] = useState<any>({})

  const getUser = async() => {
    const user =  await Auth.currentAuthenticatedUser();
    updateGroup(user.signInUserSession.accessToken.payload["cognito:groups"])
    console.log(user.signInUserSession.accessToken.payload["cognito:groups"])
  }

  useEffect(() => {
    getUser()
  }, [])

  return (
    <>
      {
        group === 'admin' ? (
          <h1>管理者画面</h1>
        ) : (
          <h1>メンバー画面</h1>
        )
      }
      <button onClick={ () => signOut() }>ログアウト</button>
      <h1>Todos</h1>
      <button onClick={() => getTodo()}>get todos!</button>
      <div>
        <ShowTodo/>
      </div>
    </>
  )
スクリーンショット 2020-07-05 19.54.16.png
广告
将在 10 秒后关闭
bannerAds