nodejsとgraphqlを使用して独自の認証APIを作成します
認証は、GraphQLを新しい開発者にとって最も挑戦的なタスクの1つです。簡単に設定できるORMの選択、安全なトークンとハッシュのパスワードを生成する方法、さらには使用するHTTPライブラリさえも使用する方法など、多くの技術的な考慮事項が関係しています。
この記事では、ローカル認証に焦点を当てています。これはおそらく、最新のWebサイトが認証を処理する最も一般的な方法であり、ユーザーのメールとパスワードを要求することで達成されます(Google認証を使用するのではなく)。
さらに、この記事では、Apollo Server 2、JSON Web Tokens(JWT)を使用し、ormを続編してnode.js認証APIを作成します。
認証処理
システムにログインします:
- 認証は、ユーザーを識別または認証します。
- 認証されたユーザーがアクセスできるルート(またはアプリケーションの一部)の検証を許可します。
このプロセスを実装する手順は次のとおりです。
- ユーザーはパスワードと電子メールで登録します。
- ユーザーの資格情報はデータベースに保存されます。
- 登録が完了すると、ユーザーはログインページにリダイレクトされます。
- 認証後、ユーザーは特定のリソースへのアクセスが許可されます。
- ユーザーのステータスは、ブラウザストレージメディア(LocalStorage、Cookie、セッションなど)またはJWTに保存されます。
前提条件
より深く入る前に、ここに従う必要があるいくつかのステップがあります。
- node.js 6以降
- 糸(推奨)またはNPM
- GraphQlの遊び場
- graphqlとnode.jsの基本
- …知識を求める心!
依存関係
これが長いリストです、始めましょう:
- Apollo Server :あらゆるタイプのGraphQLクライアントと互換性のあるオープンソースGraphQLサーバー。このプロジェクトでは、Expressはサーバーとして使用しません。代わりに、Apollo Serverの機能を活用してGraphQL APIを公開します。
- bcryptjs :ユーザーパスワードをデータベースにハッシュしたい。そのため、BCRYPTを使用します。安全な乱数を取得するために、 Web Crypto APIのGetRandomValuesインターフェイスに依存しています。
- dotenv :dotenvを使用して、.envファイルから環境変数をロードします。
- JSONWEBTOKEN :ユーザーがログインした後、後続の各リクエストにはJWTが含まれ、ユーザーがトークンを使用して許可されているルート、サービス、およびリソースにアクセスできるようにします。 JsonWebtokenは、ユーザーのIDの検証に使用されるJWTSを生成するために使用されます。
- Nodemon :ディレクトリの変更が検出されたときにノードアプリケーションを自動的に再起動することにより、ノードベースのアプリケーションの開発に役立つツール。コードが変更されるたびにサーバーをシャットダウンして開始することは望ましくありません。 Nodemonは、毎回アプリケーションの変更をチェックし、サーバーを自動的に再起動します。
- MySQL2 :node.jsのSQLクライアント。移行を実行できるように、SQLサーバーに接続する必要があります。
- 後遺症:Sequelizeは、Postgres、MySQL、Mariadb、SQLite、Microsoft SQL Serverで使用される約束ベースのノードORMです。続編を使用して、移行とモデルを自動的に生成します。
- CLIの後遺症:CLIの後遺症を使用して、後遺症コマンドを実行します。 Yarn add -Global Sequelize-Cliを使用して、端末にグローバルにインストールします。
ディレクトリ構造と開発環境の設定
真新しいプロジェクトを作成しましょう。新しいフォルダーを作成し、その中に次のように作成します。
<code>yarn init -y</code>
-yフラグとは、すべてのyarn initの問題に対して[はい]を選択し、デフォルト値を使用することを意味します。
また、Package.jsonファイルをフォルダーに配置する必要があるため、プロジェクトの依存関係をインストールしましょう。
<code>yarn add apollo-server bcryptjs dotenv jsonwebtoken nodemon sequelize sqlite3</code>
次に、開発環境にバベルを追加しましょう。
<code>yarn add babel-cli babel-preset-env babel-preset-stage-0 --dev</code>
それでは、Babelを構成しましょう。ターミナルでタッチ.babelrcを実行します。これにより、Babel構成ファイルが作成されて開きます。ここでは、以下を追加します。
<code>{ "presets": ["env", "stage-0"] }</code>
サーバーがデータを開始して移行した場合、さらに優れています。これを次のように更新することで、これを自動的に行うことができます。
<code>"scripts": { "migrate": " sequelize db:migrate", "dev": "nodemon src/server --exec babel-node -e js", "start": "node src/server", "test": "echo \"Error: no test specified\" && exit 1" },</code>
これが現在の完全なPackage.jsonファイルです。
<code>{ "name": "graphql-auth", "version": "1.0.0", "main": "index.js", "scripts": { "migrate": " sequelize db:migrate", "dev": "nodemon src/server --exec babel-node -e js", "start": "node src/server", "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "apollo-server": "^2.17.0", "bcryptjs": "^2.4.3", "dotenv": "^8.2.0", "jsonwebtoken": "^8.5.1", "nodemon": "^2.0.4", "sequelize": "^6.3.5", "sqlite3": "^5.0.0" }, "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.7.0", "babel-preset-stage-0": "^6.24.1" } }</code>
開発環境が設定されたので、データベースに移動しましょう。そこに物事を保存します。
データベース設定
MySQLをデータベースとして使用し、リレーショナルマッピングにORMの後遺症を使用します。 Initの後遺症を実行します(以前にグローバルにインストールしたことがあると仮定します)。このコマンドは、 /config /モデルと /移行の3つのフォルダーを作成する必要があります。現時点では、プロジェクトディレクトリ構造が形成されています。
データベースを構成しましょう。まず、プロジェクトルートディレクトリに.ENVファイルを作成し、以下を貼り付けます。
<code>NODE_ENV=development DB_HOST=localhost DB_USERNAME= DB_PASSWORD= DB_NAME=</code>
次に、作成したばかりの /configフォルダーに移動し、そのconfig.jsonファイルをconfig.jsに変更します。次に、次のコードを入れます。
<code>require('dotenv').config() const dbDetails = { username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, host: process.env.DB_HOST, dialect: 'mysql' } module.exports = { development: dbDetails, production: dbDetails }</code>
ここでは、.envファイルで設定したデータベースの詳細を読み取ります。 Process.ENVは、システム環境の現在の状態を表すためにノードによって注入されたグローバル変数です。
適切なデータでデータベースの詳細を更新しましょう。 SQLデータベースを開き、GraphQL_Authという名前のテーブルを作成します。 LaRagonをローカルサーバーとして使用し、PHPMyAdminを使用してデータベーステーブルを管理しています。
何を使用しても、最新情報を使用して.ENVファイルを更新する必要があります。
<code>NODE_ENV=development DB_HOST=localhost DB_USERNAME=graphql_auth DB_PASSWORD= DB_NAME=</code>
続編を設定しましょう。プロジェクトのルートディレクトリに.sequelizercファイルを作成し、以下を貼り付けます。
<code>const path = require('path') module.exports = { config: path.resolve('config', 'config.js') }</code>
次に、構成をモデルに統合しましょう。 /モデルフォルダーのindex.jsに移動し、config変数を編集します。
<code>const config = require(__dirname '/../../config/config.js')[env]</code>
最後に、モデルを書きましょう。このプロジェクトには、ユーザーモデルが必要です。続編を使用してモデルを自動的に生成しましょう。ターミナルで実行するために実行する必要があるものは次のとおりです。
<code>sequelize model:generate --name User --attributes username:string,email:string,password:string</code>
作成したモデルを編集しましょう。 user.js in /modelsフォルダーに移動し、次のことを貼り付けます。
<code>'use strict'; module.exports = (sequelize, DataTypes) => { const User = sequelize.define('User', { username: { type: DataTypes.STRING, }, email: { type: DataTypes.STRING, }, password: { type: DataTypes.STRING, } }, {}); return User; };</code>
ここでは、ユーザー名、電子メール、パスワードのプロパティとフィールドを作成します。移行を実行して、スキーマの変更を追跡しましょう。
<code>yarn migrate</code>
それでは、パターンとパーサーを書きましょう。
スキーマとパーサーをGraphQLサーバーと統合します
このセクションでは、パターンを定義し、パーサー関数を書き込み、サーバーに公開します。
モデル
SRCフォルダーで、 /schemaという名前の新しいフォルダーを作成し、schema.jsという名前のファイルを作成します。次のコードを貼り付けます。
<code>const { gql } = require('apollo-server') const typeDefs = gql` type User { id: Int! username: String email: String! } type AuthPayload { token: String! user: User! } type Query { user(id: Int!): User allUsers: [User!]! me: User } type Mutation { registerUser(username: String, email: String!, password: String!): AuthPayload! login (email: String!, password: String!): AuthPayload! } ` module.exports = typeDefs</code>
ここでは、Apollo-ServerからGraphQL-TAGをインポートします。 Apollo Serverは、GQLでパターンをラップする必要があります。
パーサー
SRCフォルダーで、 /resolversという名前の新しいフォルダーを作成し、Resolver.jsという名前のファイルを作成します。次のコードを貼り付けます。
<code>const bcrypt = require('bcryptjs') const jsonwebtoken = require('jsonwebtoken') const models = require('../models') require('dotenv').config() const resolvers = { Query: { async me(_, args, { user }) { if(!user) throw new Error('You are not authenticated') return await models.User.findByPk(user.id) }, async user(root, { id }, { user }) { try { if(!user) throw new Error('You are not authenticated!') return models.User.findByPk(id) } catch (error) { throw new Error(error.message) } }, async allUsers(root, args, { user }) { try { if (!user) throw new Error('You are not authenticated!') return models.User.findAll() } catch (error) { throw new Error(error.message) } } }, Mutation: { async registerUser(root, { username, email, password }) { try { const user = await models.User.create({ username, email, password: await bcrypt.hash(password, 10) }) const token = jsonwebtoken.sign( { id: user.id, email: user.email}, process.env.JWT_SECRET, { expiresIn: '1y' } ) return { token, id: user.id, username: user.username, email: user.email, message: "Authentication succesfull" } } catch (error) { throw new Error(error.message) } }, async login(_, { email, password }) { try { const user = await models.User.findOne({ where: { email }}) if (!user) { throw new Error('No user with that email') } const isValid = await bcrypt.compare(password, user.password) if (!isValid) { throw new Error('Incorrect password') } // return jwt const token = jsonwebtoken.sign( { id: user.id, email: user.email}, process.env.JWT_SECRET, { expiresIn: '1d'} ) return { token, user } } catch (error) { throw new Error(error.message) } } }, } module.exports = resolvers</code>
たくさんのコードがあります、そこで何が起こっているのか見てみましょう。
まず、モデルであるBcrypt、およびJSonWebtokenをインポートし、環境変数を初期化します。
次はパーサー関数です。クエリパーサーには、3つの関数(私、ユーザー、およびオルサー)があります。
- MEクエリは、現在ログインしているユーザーの詳細情報を取得します。ユーザーオブジェクトをコンテキストパラメーターとして受け入れます。コンテキストは、クエリに記載されているIDを介してユーザーデータをロードするために使用されるデータベースへのアクセスを提供するために使用されます。
- ユーザークエリは、ユーザーのIDに基づいてユーザーの詳細情報を取得します。 IDをコンテキストパラメーターとユーザーオブジェクトとして受け入れます。
- Alluserクエリは、すべてのユーザーの詳細を返します。
ユーザーステータスがログインされている場合、ユーザーはオブジェクトになります。ユーザーがログインしていない場合、ユーザーはnullになります。このユーザーを突然変異して作成します。
Mutation Parserには、2つの機能(RegisterUserとLoglogluser)があります。
- RegisterUserは、ユーザーのユーザー名、電子メール、およびパスワードを受け入れ、これらのフィールドを使用してデータベースに新しい行を作成します。 bcryptjsパッケージを使用して、bcrypt.hash(パスワード、10)を使用してユーザーのパスワードをハッシュすることに注意する必要があります。 jsonwebtoken.sign与えられたペイロードをJSON Webトークン文字列(この場合はユーザーIDと電子メール)に同期して署名します。最後に、RegisterUserが成功した場合はJWT文字列とユーザープロファイルを返します。エラーが発生した場合、エラーメッセージが返されます。
- ログインは電子メールとパスワードを受け入れ、これらの詳細が提供された詳細と一致するかどうかを確認します。まず、ユーザーデータベースのどこかに電子メール値が既に存在するかどうかを確認します。
<code>models.User.findOne({ where: { email }}) if (!user) { throw new Error('No user with that email') }</code>
次に、bcryptのbcrypt.compareメソッドを使用して、パスワードが一致するかどうかを確認します。
<code>const isValid = await bcrypt.compare(password, user.password) if (!isValid) { throw new Error('Incorrect password') }</code>
次に、以前にRegisterUserでやったように、JSONWeBtoken.Signを使用してJWT文字列を生成します。ログイン変異は、トークンとユーザーオブジェクトを返します。
次に、jwt_secretを.envファイルに追加しましょう。
<code>JWT_SECRET=一个非常长的秘密</code>
サーバ
最後に、それはサーバーです!プロジェクトのルートフォルダーにserver.jsを作成し、以下を貼り付けます。
<code>const { ApolloServer } = require('apollo-server') const jwt = require('jsonwebtoken') const typeDefs = require('./schema/schema') const resolvers = require('./resolvers/resolvers') require('dotenv').config() const { JWT_SECRET, PORT } = process.env const getUser = token => { try { if (token) { return jwt.verify(token, JWT_SECRET) } return null } catch (error) { return null } } const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { const token = req.get('Authorization') || '' return { user: getUser(token.replace('Bearer', ''))} }, introspection: true, playground: true }) server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => { console.log(`? Server ready at ${url}`); });</code>
ここでは、スキーマ、リゾルバー、JWTをインポートし、環境変数を初期化します。最初に、検証を使用してJWTトークンを確認します。 JWT.Verifyは、トークンとJWTキーをパラメーターとして受け入れます。
次に、TypedefsとResolversを受け入れるApolloserverインスタンスを使用してサーバーを作成します。
サーバーがあります!ターミナルでYarn Devを実行することから始めましょう。
APIをテストします
次に、GraphQL Playgroundを使用してGraphQL APIをテストしましょう。 IDを介して、個々のユーザーを含むすべてのユーザーを登録、ログイン、および表示できるはずです。
まず、GraphQL Playgroundアプリを開くか、ブラウザにLocalHost:// 4000を開き、アクセスします。
登録ユーザーの突然変異
<code>mutation { registerUser(username: "Wizzy", email: "[email protected]", password: "wizzyekpot" ){ token } }</code>
このような結果を得る必要があります:
<code>{ "data": { "registerUser": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzAwLCJleHAiOjE2MzA3OTc5MDB9.gmeynGR9Zwng8cIJR75Qrob9bovnRQT242n6vfBt5PY" } } }</code>
ログイン変異
次に、作成したばかりのユーザーの詳細でログインしましょう。
<code>mutation { login(email:"[email protected]" password:"wizzyekpot"){ token } }</code>
このような結果を得る必要があります:
<code>{ "data": { "login": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzcwLCJleHAiOjE1OTkzMjY3NzB9.PDiBKyq58nWxlgTOQYzbtKJ-HkzxemVppLA5nBdm4nc" } } }</code>
素晴らしい!
個々のユーザーのクエリ
単一のユーザーを照会するには、ユーザートークンを承認ヘッダーとして渡す必要があります。 HTTPヘッダータブに移動します。
...そして、このコンテンツを貼り付けます:
<code>{ "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzcwLCJleHAiOjE1OTkzMjY3NzB9.PDiBKyq58nWxlgTOQYzbtKJ-HkzxemVppLA5nBdm4nc" }</code>
これがクエリです:
<code>query myself{ me { id email username } }</code>
このような結果を得る必要があります:
<code>{ "data": { "me": { "id": 15, "email": "[email protected]", "username": "Wizzy" } } }</code>
素晴らしい!それでは、IDでユーザーを取得しましょう。
<code>query singleUser{ user(id:15){ id email username } }</code>
これがすべてのユーザーを取得するためのクエリです:
<code>{ allUsers{ id username email } }</code>
要約します
認証は、認証が必要なWebサイトを構築する際の最も難しいタスクの1つです。 GraphQLを使用すると、1つのエンドポイントのみを使用して完全な認証APIを構築できます。 SQLデータベースとの関係を簡単に作成できるため、ORMを続編するため、モデルについて心配する必要はほとんどありません。また、HTTPサーバーライブラリ(Expressなど)は必要ありませんが、Apollo GraphQLをミドルウェアとして使用する必要はありません。 Apollo Server 2により、独自のライブラリに依存しないGraphQLサーバーを作成できるようになりました。
GitHubのこのチュートリアルについては、ソースコードを確認してください。
以上がnodejsとgraphqlを使用して独自の認証APIを作成しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Google Fontsが新しいデザイン(ツイート)を展開したようです。最後の大きな再設計と比較して、これははるかに反復的です。違いをほとんど伝えることができません

プロジェクトにカウントダウンタイマーが必要だったことはありますか?そのようなことのために、プラグインに手を伸ばすのは自然なことかもしれませんが、実際にはもっとたくさんあります

新しいプロジェクトの開始時に、SASSコンピレーションは瞬く間に起こります。これは、特にbrowsersyncとペアになっている場合は素晴らしい気分です。

タータンは、スコットランド、特にファッショナブルなキルトに通常関連する模様のある布です。 Tartanify.comでは、5,000を超えるTartanを集めました

インラインテンプレートディレクティブにより、既存のWordPressマークアップに対する進行性の強化として、リッチVUEコンポーネントを構築できます。

PHPテンプレートは、多くの場合、サブパーコードを促進するために悪いラップを取得しますが、そうである必要はありません。 PHPプロジェクトが基本を実施する方法を見てみましょう

私たちは常にWebをよりアクセスしやすくしたいと考えています。色のコントラストは単なる数学なので、SASSはデザイナーが見逃したかもしれないエッジケースをカバーするのに役立ちます。
