Let ' s Buat API Pengesahan Sendiri dengan NodeJs dan Graphql
Pengesahan adalah salah satu tugas yang paling mencabar untuk pemaju baru ke GraphQL. Terdapat banyak pertimbangan teknikal yang terlibat, termasuk memilih ORM yang mudah ditetapkan, bagaimana untuk menghasilkan kata laluan token dan hash yang selamat, dan juga perpustakaan HTTP yang digunakan dan cara menggunakannya.
Artikel ini memberi tumpuan kepada pengesahan tempatan . Ini mungkin cara yang paling popular untuk laman web moden untuk mengendalikan pengesahan, yang dicapai dengan meminta e -mel dan kata laluan pengguna (berbanding dengan penggunaan Google Authentication).
Di samping itu, artikel ini menggunakan Apollo Server 2, JSON Web Tokens (JWT) dan Sequelize Orm untuk membina API Pengesahan Node.js.
Pemprosesan pengesahan
Log masuk ke sistem:
- Pengesahan mengenal pasti atau mengesahkan pengguna.
- Membenarkan pengesahan laluan (atau bahagian aplikasi) yang boleh diakses oleh pengguna yang disahkan.
Langkah -langkah untuk melaksanakan proses ini adalah seperti berikut:
- Pengguna mendaftar dengan kata laluan dan e -mel.
- Kelayakan pengguna disimpan dalam pangkalan data.
- Selepas pendaftaran selesai, pengguna akan diarahkan ke halaman log masuk.
- Selepas pengesahan, pengguna akan diberikan akses kepada sumber tertentu.
- Status pengguna disimpan dalam mana -mana medium penyimpanan penyemak imbas (misalnya, localStorage, cookies, sesi) atau dalam JWT.
Prasyarat
Sebelum anda pergi lebih mendalam, berikut adalah beberapa langkah yang perlu anda ikuti.
- Node.js 6 atau lebih tinggi
- Benang (disyorkan) atau npm
- Graphql Playground
- Asas Graphql dan Node.js
- ... hati yang mencari pengetahuan!
Kebergantungan
Berikut adalah senarai panjang, mari kita mulakan:
- Server Apollo : Pelayan GraphQL Sumber Terbuka yang serasi dengan mana -mana jenis klien GraphQL. Dalam projek ini, kami tidak akan menggunakan Express sebagai pelayan kami. Sebaliknya, kami akan memanfaatkan keupayaan pelayan Apollo untuk mendedahkan API GraphQL kami.
- BCRYPTJS : Kami mahu hash kata laluan pengguna ke dalam pangkalan data kami. Itulah sebabnya kami akan menggunakan Bcrypt. Ia bergantung pada antara muka GetRandomValues API Crypto Web untuk mendapatkan nombor rawak yang selamat.
- Dotenv : Kami akan menggunakan dotenv untuk memuatkan pembolehubah persekitaran dari fail .env kami.
- JSONWEBTOKEN : Selepas log pengguna masuk, setiap permintaan berikutnya akan mengandungi JWT, yang membolehkan pengguna mengakses laluan, perkhidmatan, dan sumber yang dibenarkan menggunakan token. JsonWebtoken akan digunakan untuk menjana JWTS, yang digunakan untuk mengesahkan identiti pengguna.
- Nodemon : Alat yang membantu membangunkan aplikasi berasaskan nod dengan memulakan semula aplikasi nod secara automatik apabila perubahan direktori dikesan. Kami tidak mahu pelayan ditutup dan bermula setiap kali kod berubah. Nodemon memeriksa perubahan dalam aplikasi kami setiap kali dan secara automatik memulakan semula pelayan.
- MySQL2 : Node.js 'SQL Client. Kami memerlukannya untuk menyambung ke pelayan SQL kami supaya kami dapat menjalankan penghijrahan.
- Sequelize : Sequelize adalah nod berasaskan janji yang digunakan dalam Postgres, MySQL, MariaDB, SQLite dan Microsoft SQL Server. Kami akan menggunakan Sequelize untuk menghasilkan migrasi dan model kami secara automatik.
- Sequelize CLI : Kami akan menggunakan CLI Sequel untuk menjalankan perintah Sequel. Pasangnya secara global di terminal menggunakan benang tambah-global sekuel-cli.
Menyediakan struktur direktori dan persekitaran pembangunan
Mari buat projek baru. Buat folder baru dan buat perkara berikut di dalamnya:
<code>yarn init -y</code>
Bendera -Bendera bermakna kita memilih ya untuk semua isu benang init dan gunakan nilai lalai.
Kami juga harus meletakkan fail pakej.json dalam folder, jadi mari pasang kebergantungan projek:
<code>yarn add apollo-server bcryptjs dotenv jsonwebtoken nodemon sequelize sqlite3</code>
Seterusnya, mari tambahkan Babel ke persekitaran pembangunan kita:
<code>yarn add babel-cli babel-preset-env babel-preset-stage-0 --dev</code>
Sekarang, mari kita konfigurasikan Babel. Jalankan sentuhan .babelrc di terminal. Ini akan membuat dan membuka fail konfigurasi Babel di mana kami akan menambah yang berikut:
<code>{ "presets": ["env", "stage-0"] }</code>
Lebih baik jika pelayan kami memulakan dan memindahkan data. Kami boleh melakukan ini secara automatik dengan mengemas kini Package.json dengan yang berikut:
<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>
Inilah fail Pakej.JSON Lengkap semasa kami:
<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>
Sekarang persekitaran pembangunan kami ditubuhkan, mari kita beralih ke pangkalan data, kami akan menyimpan perkara di sana.
Tetapan pangkalan data
Kami akan menggunakan MySQL sebagai pangkalan data kami dan menggunakan Orm Sequelize untuk pemetaan relasi. Run Sequelize init (dengan asumsi anda telah memasangnya secara global sebelum ini). Perintah ini harus membuat tiga folder: /config /model dan /migrasi. Pada masa ini, struktur direktori projek kami terbentuk.
Mari kita konfigurasikan pangkalan data kami. Pertama, buat fail .env dalam direktori root projek dan tampal yang berikut:
<code>NODE_ENV=development DB_HOST=localhost DB_USERNAME= DB_PASSWORD= DB_NAME=</code>
Kemudian pergi ke folder /konfigurasi kami hanya membuat dan menamakan semula fail config.json di dalamnya ke config.js. Kemudian, letakkan kod berikut ke dalamnya:
<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>
Di sini kita membaca butiran pangkalan data yang kita tetapkan dalam fail .env. Process.env adalah pemboleh ubah global yang disuntik oleh nod untuk mewakili keadaan semasa persekitaran sistem.
Mari kita kemas kini butiran pangkalan data kami dengan data yang sesuai. Buka pangkalan data SQL dan buat jadual bernama Graphql_Auth. Saya menggunakan Laragon sebagai pelayan tempatan saya dan menggunakan phpMyAdmin untuk menguruskan jadual pangkalan data.
Tidak kira apa yang anda gunakan, kami perlu mengemas kini fail .env dengan maklumat terkini:
<code>NODE_ENV=development DB_HOST=localhost DB_USERNAME=graphql_auth DB_PASSWORD= DB_NAME=</code>
Mari kita konfigurasi sekuel. Buat fail .seakeSeelizerc dalam direktori root projek dan tampal yang berikut:
<code>const path = require('path') module.exports = { config: path.resolve('config', 'config.js') }</code>
Sekarang mari kita mengintegrasikan konfigurasi kita ke dalam model. Pergi ke folder index.js dalam /model dan edit pembolehubah konfigurasi.
<code>const config = require(__dirname '/../../config/config.js')[env]</code>
Akhirnya, mari kita tulis model kami. Untuk projek ini, kami memerlukan model pengguna. Mari kita gunakan Sequelize untuk menghasilkan model secara automatik. Inilah yang perlu kita jalankan di terminal untuk menetapkannya:
<code>sequelize model:generate --name User --attributes username:string,email:string,password:string</code>
Mari edit model yang dicipta untuk kita. Pergi ke user.js dalam /model folder dan tampal yang berikut:
<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>
Di sini kami membuat sifat dan bidang untuk nama pengguna, e -mel, dan kata laluan. Mari jalankan penghijrahan untuk menjejaki perubahan dalam skema kami:
<code>yarn migrate</code>
Sekarang mari kita tulis corak dan parser.
Mengintegrasikan Skema dan Parser dengan Graphql Server
Dalam bahagian ini, kami akan menentukan corak kami, menulis fungsi parser, dan mendedahkannya ke pelayan kami.
model
Dalam folder SRC, buat folder baru bernama /skema dan buat fail bernama Schema.js di dalamnya. Tampal kod berikut:
<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>
Di sini, kami mengimport GraphQL-Tag dari Apollo-server. Pelayan Apollo perlu membungkus corak kami dengan GQL.
Parser
Dalam folder SRC, buat folder baru bernama /resolvers dan buat fail bernama Resolver.js di dalamnya. Tampal kod berikut:
<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>
Terdapat banyak kod, mari kita lihat apa yang berlaku di sana.
Pertama, kami mengimport model kami, bcrypt, dan jsonwebtoken, dan kemudian memulakan pembolehubah persekitaran kami.
Seterusnya ialah fungsi parser. Dalam parser pertanyaan, kami mempunyai tiga fungsi (saya, pengguna, dan penggemar):
- Saya pertanyaan untuk mendapatkan maklumat terperinci mengenai pengguna yang sedang dilog masuk. Ia menerima objek pengguna sebagai parameter konteks. Konteks ini digunakan untuk menyediakan akses kepada pangkalan data kami, yang digunakan untuk memuatkan data pengguna melalui ID yang disediakan dalam pertanyaan.
- Pertanyaan pengguna memperoleh maklumat terperinci pengguna berdasarkan ID pengguna. Ia menerima ID sebagai parameter konteks dan objek pengguna.
- Pertanyaan Alluser mengembalikan butiran semua pengguna.
Jika status pengguna dilog masuk, pengguna akan menjadi objek; Jika pengguna tidak log masuk, pengguna akan menjadi batal. Kami akan membuat pengguna ini dalam mutasi kami.
Dalam parser mutasi, kami mempunyai dua fungsi (pendaftaran dan loginuser):
- Registeruser menerima nama pengguna, e -mel, dan kata laluan pengguna dan menggunakan medan ini untuk membuat baris baru dalam pangkalan data kami. Harus diingat bahawa kami menggunakan pakej bcryptjs untuk hash kata laluan pengguna menggunakan bcrypt.hash (kata laluan, 10). jsonwebtoken.sign secara serentak menandatangani muatan yang diberikan kepada rentetan token web JSON (dalam hal ini pengguna ID dan e -mel). Akhirnya, Registeruser akan mengembalikan rentetan JWT dan profil pengguna jika berjaya; Jika ralat berlaku, mesej ralat akan dikembalikan.
- Log masuk menerima e -mel dan kata laluan dan cek jika butiran ini sepadan dengan butiran yang disediakan. Pertama, kami periksa sama ada nilai e -mel sudah ada di dalam pangkalan data pengguna.
<code>models.User.findOne({ where: { email }}) if (!user) { throw new Error('No user with that email') }</code>
Kemudian, kami menggunakan kaedah bcrypt bcrypt.comPare untuk memeriksa sama ada kata laluan sepadan.
<code>const isValid = await bcrypt.compare(password, user.password) if (!isValid) { throw new Error('Incorrect password') }</code>
Kemudian, seperti yang kita lakukan di RegisterUser sebelum ini, kami menggunakan jsonwebtoken.sign untuk menghasilkan rentetan JWT. Log masuk mutasi pulangan token dan objek pengguna.
Sekarang mari tambahkan JWT_SECRET ke fail .Env kami.
<code>JWT_SECRET=一个非常长的秘密</code>
pelayan
Akhirnya, ia adalah pelayan! Buat server.js dalam folder root projek dan tampal yang berikut:
<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>
Di sini kami mengimport skema, penentu, dan JWT dan memulakan pembolehubah persekitaran kami. Pertama, kami menggunakan mengesahkan untuk mengesahkan token JWT. JWT.Verify menerima kunci Token dan JWT sebagai parameter.
Seterusnya, kami membuat pelayan kami menggunakan contoh Apolloserver yang menerima typedefs dan resolver.
Kami mempunyai pelayan! Mari kita mulakan dengan menjalankan benang dev di terminal.
API ujian
Sekarang mari kita menguji API GraphQL menggunakan GraphQL Playground. Kami sepatutnya dapat mendaftar, log masuk dan melihat semua pengguna - termasuk pengguna individu - melalui ID.
Kami akan terlebih dahulu membuka aplikasi GRAPHQL Playground, atau hanya membuka localhost: // 4000 dalam penyemak imbas untuk mengaksesnya.
Mutasi untuk pengguna berdaftar
<code>mutation { registerUser(username: "Wizzy", email: "[email protected]", password: "wizzyekpot" ){ token } }</code>
Kita harus mendapat hasil seperti ini:
<code>{ "data": { "registerUser": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzAwLCJleHAiOjE2MzA3OTc5MDB9.gmeynGR9Zwng8cIJR75Qrob9bovnRQT242n6vfBt5PY" } } }</code>
Mutasi log masuk
Sekarang mari log masuk dengan butiran pengguna yang baru saja kami buat:
<code>mutation { login(email:"[email protected]" password:"wizzyekpot"){ token } }</code>
Kita harus mendapat hasil seperti ini:
<code>{ "data": { "login": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzcwLCJleHAiOjE1OTkzMjY3NzB9.PDiBKyq58nWxlgTOQYzbtKJ-HkzxemVppLA5nBdm4nc" } } }</code>
Luar Biasa!
Pertanyaan untuk pengguna individu
Untuk menanyakan pengguna tunggal, kita perlu lulus token pengguna sebagai tajuk kebenaran. Pergi ke tab HTTP Header.
... dan tampal kandungan ini dalam:
<code>{ "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTUsImVtYWlsIjoiZWtwb3RAZ21haWwuY29tIiwiaWF0IjoxNTk5MjQwMzcwLCJleHAiOjE1OTkzMjY3NzB9.PDiBKyq58nWxlgTOQYzbtKJ-HkzxemVppLA5nBdm4nc" }</code>
Inilah pertanyaan:
<code>query myself{ me { id email username } }</code>
Kita harus mendapat hasil seperti ini:
<code>{ "data": { "me": { "id": 15, "email": "[email protected]", "username": "Wizzy" } } }</code>
Hebat! Sekarang mari kita dapatkan pengguna dengan ID:
<code>query singleUser{ user(id:15){ id email username } }</code>
Berikut adalah pertanyaan untuk mendapatkan semua pengguna:
<code>{ allUsers{ id username email } }</code>
Meringkaskan
Pengesahan adalah salah satu tugas yang paling sukar apabila membina laman web yang memerlukan pengesahan. GraphQL membolehkan kami membina API Pengesahan Lengkap menggunakan hanya satu titik akhir. Sequelize Orm menjadikannya begitu mudah untuk mewujudkan hubungan dengan pangkalan data SQL yang kita tidak perlu bimbang tentang model kami. Ia juga perlu diperhatikan bahawa kita tidak memerlukan perpustakaan pelayan HTTP (seperti Express) tetapi menggunakan Apollo Graphql sebagai middleware. Apollo Server 2 kini membolehkan kami membuat pelayan GraphQL bebas perpustakaan kami sendiri!
Sila periksa kod sumber untuk tutorial ini di GitHub.
Atas ialah kandungan terperinci Let ' s Buat API Pengesahan Sendiri dengan NodeJs dan Graphql. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











Saya melihat Font Google melancarkan reka bentuk baru (tweet). Berbanding dengan reka bentuk besar yang terakhir, ini terasa lebih berulang. Saya hampir tidak dapat memberitahu perbezaannya

Pernahkah anda memerlukan pemasa undur dalam projek? Untuk sesuatu seperti itu, mungkin semula jadi untuk mencapai plugin, tetapi sebenarnya lebih banyak lagi

Semua yang anda ingin tahu mengenai atribut data dalam HTML, CSS, dan JavaScript.

Pada permulaan projek baru, kompilasi SASS berlaku dalam sekejap mata. Ini terasa hebat, terutamanya apabila ia dipasangkan dengan BrowserSync, yang dimuat semula

Tartan adalah kain berpola yang biasanya dikaitkan dengan Scotland, terutamanya kilt bergaya mereka. Di Tartanify.com, kami mengumpulkan lebih dari 5,000 Tartan

Arahan template inline membolehkan kita membina komponen Vue yang kaya sebagai peningkatan progresif ke atas markup WordPress yang sedia ada.

Satu perkara yang menarik perhatian saya pada senarai ciri-ciri untuk Lea Verou ' s conic-gradient () polyfill adalah item terakhir:

Templat PHP sering mendapat rap buruk untuk memudahkan kod subpar - tetapi itu tidak perlu berlaku. Mari kita lihat bagaimana projek PHP dapat menguatkuasakan asas
