6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ApolloサーバーとPrismaを使用したJWT認証

Last updated at Posted at 2020-10-26

#はじめに
本記事ではGraphQLにおけるJWTを利用したユーザー認証についてテストを行った備忘録となります。

##Prismaとは?
GraphQLサーバー(本記事ではGraphQLサーバーとしてApolloを利用)とデータベースを繋ぐORMの一つです。

ORMとは下記の機能のまとまりのことを指します。

① データベースからデータを取得する
② 取得したデータをオブジェクト化する
③ データの更新・変更などをデータベースに格納する

参考:もっとORMを使えるようになりたいので、見直してみた

##JWTとは?
JWT(ジョット)とはJSON Web Token の略で、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内の中ほどある、portに関する設定のコメントアウトを外す。
こちらがコメントアウトされたままだと、localhostで立ち上げることが出来ません。

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として機能するために必要なファイルの元になります。

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

③prisma.ymlは変更不要ですが、下記のようになります。

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

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

準備ができたら、先ほどの「Next steps」の案内に従い、コンテナを起動させます。

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

以上のコマンドを正常に実行すると、datamodel.prismaファイルから生成されたORMとして機能するために必要なファイルが作成されます。

下記のようにPrismaインスタンスをファイルにimportすると、QueryやMutationを実行する際に、データベースへアクセス出来るようになります。

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

##Apolloサーバーに関するコードを書く

Prismaの設定が完了したら、GraphQLサーバーとして、Apolloを使用する準備をしていきます。bcryptとはパスワードのハッシュ化のために利用するライブラリです。

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

先ずはスキーマを定義します。

schema.js

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はすべてのリゾルバー間で共有するので、第三引数のcontextとして使います。

Mutation.js
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サーバー)を立ち上げする設定の処理を書きます。

index.js
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上でname,email.passwordを含むクエリを書きます。

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

JWTトークンが返ってきました。

####サインイン

続いてサインインの確認です。
サインアップと同じ、email,passwordをクエリで書きます。

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

サインアップの時と同一のJWTトークンが返ってきました!
成功です!

###おわりに

以上、GraphQLにおけるログイン認証をテストしてみました。
PrismaとDockerによって素早く環境を作ることができ、その後はほとんど意識することなく、コードを書けたのはGraphQLの強みであるように感じました。

それでは、また😊

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?