使用 Apollo 服务器和 Prisma 实现 JWT 认证

首先

本文档是关于在GraphQL中使用JWT进行用户身份验证的测试备忘录。

Prisma是什么?

这是一种将GraphQL服务器(本文使用Apollo作为GraphQL服务器)和数据库连接的ORM。

ORM 指的是下列功能的整合。

1. 从数据库中获取数据。
2. 将获取的数据转换为对象。
3. 将数据的更新、修改等存储到数据库中。

参考:因为想要更加熟练地使用ORM,所以重新审视了一下。

JWT是什么?

JWT(JSON Web Token)是JSON Web令牌的缩写,指的是在JSON数据上应用签名和加密的方法。
本文将介绍其在登录认证中的应用。
请点击这里查看详细信息。

Prisma的设置

我们立即从Prisma的设置开始吧?

$ mkdir jwt-Auth
$ cd jwt-Auth
$ npm init
$ npm install apollo-server graphql  prisma-client-lib
$ npm install -g prisma

完成npm安装后,将在项目中进行配置,以便使用Prisma。

$ prisma init

直接使用Docker,并进行Prisma配置。

? Set up a new Prisma server or deploy to an existing server? 
❯ Create new database                 Set up a local database using Docker 
? What kind of database do you want to deploy to? 
❯ PostgreSQL        PostgreSQL database 
? Select the programming language for the generated Prisma client 
❯ Prisma JavaScript Client

当你成功时,将显示以下的指引。

Created 3 new files:                                                                          

  prisma.yml           Prisma service definition
  datamodel.graphql    GraphQL SDL-based datamodel (foundation for database)
  docker-compose.yml   Docker configuration file

Next steps:

  1. Start your Prisma server: docker-compose up -d
  2. Deploy your Prisma service: prisma deploy
  3. Read more about Prisma server:

启动Docker容器

在启动Docker容器之前,对生成的文件进行配置更改。

请取消注释docker-compose.yml文件中关于端口设置的部分。
如果保持注释状态,将无法在本地主机上启动。

# Uncomment the next two lines to connect to your your database from outside the Docker environment, e.g. using a database GUI like Postico
    ports:
      - "5432:5432"

我将会修改datamodel.graphql文件。这个文件是作为ORM(对象关系映射)所必需的文件的基础。

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
}

③请不要更改prisma.yml,以下是配置文件的内容。

endpoint: http://localhost:4466
datamodel: datamodel.prisma

generate:
  - generator: javascript-client
    output: ./generated/prisma-client/

当准备好之后,请按照先前提供的“下一步”指南启动容器。

$ docker-compose up -d 
$ prisma deploy
$ prisma generate

当成功执行以上命令时,将会创建所需的文件,以作为由datamodel.prisma文件生成的ORM的功能。

如果将Prisma实例导入到文件中,那么在执行Query和Mutation时,就可以访问数据库。

const { prisma } = require('./generated/prisma-client')

编写与Apollo服务器相关的代码

完成 Prisma 设置后,我们将准备使用 Apollo 作为 GraphQL 服务器。bcrypt 是用于密码哈希处理的库。

$ mkdir resolver 
$ touch index.js schema.js  resolver/Mutation.js 
$ npm install bcrypt jsonwebtoken

首先,我们要定义模式。


const {gql} = require('apollo-server');

const typeDefs = gql`
type Query {
  users(query: String): [User!]!
}

type Mutation {
  createUser(data: CreateUserInput!): AuthPayload!
  login(data: LoginUserInput!): AuthPayload!
}

type AuthPayload {
  token: String!
  user: User!
}

input CreateUserInput {
  name: String!
  email: String!
  password: String!
}

input LoginUserInput {
  email: String!
  password: String!
}

type User {
  id: ID!
  name: String!
  email: String
  password: String!
}
`
module.exports = typeDefs;

我们在这里使用JWT和bcrypt。
Prisma将在所有解析器之间共享,作为第三个参数的上下文来使用。

const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const Mutation = {
    async createUser(parent, args, { prisma }, info) {
        const { data: { email, name, password } } = args;
        const newUser = await prisma.createUser({
          email,
          name,
          // bcryptでパスワードをハッシュ化
          password: bcrypt.hashSync(password, 3)
        });
          // サーバーがJWTトークンを発行
        return {token : jwt.sign(newUser, "supersecret")};
    },
    async login(parent, args, { prisma }, info) {
        const { data: { email, password } } = args;
         // メールアドレスと照合
        const [ signInUser ] = await prisma.users({
          where: {
            email
          }
        })
       // console.log(signInUser) 該当ユーザーのid,name,email,passwordが格納されているオブジェクト
        if (!signInUser) throw new Error('Unable to Login');
         // 暗号化されたデータベース格納のパスワードと照合
        const isMatch = bcrypt.compareSync(password, signInUser.password);
        if (!isMatch) throw new Error('Unable to Login');
         // 一致した場合、新しいユーザ認証トークンを戻り値として返す
        return {token : jwt.sign(signInUser, "supersecret")};
    },
}

module.exports = Mutation

我們來寫最後一步,即啟動Apollo服務器(GraphQL服務器)的設置處理。

const { ApolloServer } = require('apollo-server');
const Mutation = require('./resolver/Mutation')
const typeDefs = require('./schema')
// datamodel.prismaファイルから生成されたPrismaインスタンス
const { prisma } = require('./generated/prisma-client')


const server = new ApolloServer({
    typeDefs: typeDefs,
    resolvers: {
        Mutation
    },
    context: {
        prisma
    }
})

server.listen().then(({ url}) => {
    console.log(`? Server ready at ${url}`);
});

在GraphQL IDE中进行测试

使用GraphQL IDE进行测试。

$ node index.js
? Server ready at http://localhost:4000/

注册

我将在IDE上编写一个查询,其中包含名称、电子邮件和密码。

スクリーンショット 2020-10-27 1.44.28.png

返回了JWT令牌。

登入 rù)

接下来是签到确认。
与注册相同,将电子邮件和密码写在查询中。

スクリーンショット 2020-10-27 1.46.10.png

成功!返回的JWT令牌与注册时相同!

最后

我尝试在GraphQL中测试了登录认证功能,利用Prisma和Docker可以快速搭建环境,接下来几乎无需意识,可以轻松编写代码,这正是GraphQL的优势所在。

那么,再见?

bannerAds