GraphQL - Mengautentikasi Klien
Otentikasi adalah proses atau tindakan memverifikasi identitas pengguna atau proses. Aplikasi harus mengautentikasi pengguna untuk memastikan bahwa data tidak tersedia untuk pengguna anonim. Di bagian ini, kita akan mempelajari cara mengotentikasi klien GraphQL.
JWT Ekspres
Dalam contoh ini, kami akan menggunakan jQuery untuk membuat aplikasi klien. Untuk mengotentikasi permintaan, kami akan menggunakan express-jwt modul di sisi server.
Modul express-jwt adalah middleware yang memungkinkan Anda mengautentikasi permintaan HTTP menggunakan token JWT. JSON Web Token (JWT) adalah string panjang yang mengidentifikasi pengguna yang masuk.
Setelah pengguna berhasil masuk, server menghasilkan token JWT. Token ini dengan jelas mengidentifikasi log. Dengan kata lain, token merupakan representasi dari identitas pengguna. Jadi lain kali, ketika klien datang ke server, ia harus menunjukkan token ini untuk mendapatkan sumber daya yang diperlukan. Klien dapat berupa aplikasi seluler atau aplikasi web.
Ilustrasi
Kami akan mengikuti prosedur langkah-bijaksana untuk memahami ilustrasi ini.
Menyiapkan Server
Berikut adalah langkah-langkah untuk menyiapkan server -
Langkah 1 - Unduh dan Instal Dependensi yang Diperlukan untuk Proyek
Buat folder auth-server-app. Ubah direktori Anda menjadi auth-server-app dari terminal. Ikuti langkah 3 hingga 5 yang dijelaskan di bab Pengaturan Lingkungan.
Langkah 2 - Buat Skema
Menambahkan schema.graphql file di folder proyek auth-server-app dan tambahkan kode berikut -type Query
{
greetingWithAuth:String
}
Langkah 3 - Tambahkan Resolver
Buat file resolvers.js di folder proyek dan tambahkan kode berikut -
Penyelesai akan memverifikasi apakah objek pengguna yang diautentikasi tersedia dalam objek konteks GraphQL. Ini akan memunculkan pengecualian jika pengguna yang diautentikasi tidak tersedia.
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
Langkah 4 - Buat File Server.js
Middleware otentikasi mengotentikasi pemanggil menggunakan JSON Web Token. URL untuk otentikasi adalah http://localhost:9000/login.
Ini adalah operasi pasca. Pengguna harus mengirimkan email dan kata sandinya yang akan divalidasi dari backend. Jika token yang valid dibuat menggunakan metode jwt.sign, klien harus mengirimkan ini di header untuk permintaan selanjutnya.
Jika tokennya valid, req.user akan disetel dengan objek JSON yang didekodekan untuk digunakan oleh middleware selanjutnya untuk otorisasi dan kontrol akses.
Kode berikut menggunakan dua modul - jsonwebtoken dan express-jwt untuk mengautentikasi permintaan -
Saat pengguna mengklik file greettombol, permintaan untuk rute / graphql dikeluarkan. Jika pengguna tidak diautentikasi, dia akan diminta untuk mengautentikasi dirinya sendiri.
Pengguna diberikan formulir yang menerima id email dan kata sandi. Dalam contoh kami, / login route bertanggung jawab untuk mengautentikasi pengguna.
Rute / login memverifikasi jika ditemukan kecocokan dalam database untuk kredensial yang diberikan oleh pengguna.
Jika kredensial tidak valid, pengecualian HTTP 401 dikembalikan kepada pengguna.
Jika kredensial valid, token dibuat oleh server. Token ini dikirim sebagai bagian dari tanggapan kepada pengguna. Ini dilakukan oleh fungsi jwt.sign.
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
Untuk setiap permintaan, fungsi app.use () akan dipanggil. Ini pada gilirannya akan memanggil middleware expressJWT. Middleware ini akan memecahkan kode JSON Web Token. ID pengguna yang disimpan dalam token akan diambil dan disimpan sebagai pengguna properti di objek permintaan.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Untuk menyediakan properti pengguna dalam konteks GraphQL, properti ini ditugaskan ke file context objek seperti yang ditunjukkan di bawah ini -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Membuat server.js di jalur folder saat ini. File server.js lengkap adalah sebagai berikut -
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt'); //auth
const jwt = require('jsonwebtoken'); //auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
Langkah 5 - Jalankan Aplikasi
Jalankan perintah npm start di terminal. Server akan aktif dan berjalan pada 9000 port. Di sini, kami menggunakan GraphiQL sebagai klien untuk menguji aplikasi.
Buka browser dan ketik URL-nya http://localhost:9000/graphiql. Ketik kueri berikut di editor -
{
greetingWithAuth
}
Dalam respons di bawah ini, kami mendapat kesalahan karena kami bukan pengguna yang diautentikasi.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Di bagian selanjutnya, mari kita buat aplikasi klien untuk mengautentikasi.
Menyiapkan Klien JQuery
Dalam aplikasi klien, tombol salam disediakan yang akan memanggil skema greetingWithAuth. Jika Anda mengklik tombol tanpa login, itu akan memberi Anda pesan kesalahan seperti di bawah ini -
Setelah Anda masuk dengan pengguna yang tersedia di database, layar berikut akan muncul -
Untuk mengakses greeting, kita perlu mengakses URL terlebih dahulu http://localhost:9000/login rute seperti di bawah ini.
Responsnya akan berisi token yang dihasilkan dari server.
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
.html("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
Setelah berhasil login, kita dapat mengakses greetingWithAuth skema seperti yang diberikan di bawah ini. Harus ada Authorizationheader untuk semua permintaan berikutnya dengan token pembawa.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Berikut ini adalah kode untuk index.html -
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
let loginToken = "";
$("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken},
type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}` }),
success: function(result) {
$("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv").html('please authenticate first!!')
.css({"color":"red",'font-weight':'bold'})
return;
}
$("#greetingDiv").html('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() {
var email = $("#txtEmail").val();
var password = $("#txtPwd").val();
if(email && password) {
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
.html("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>