GraphQL - İstemci Kimlik Doğrulaması
Kimlik doğrulama, bir kullanıcının veya işlemin kimliğini doğrulama işlemi veya eylemidir. Verilerin anonim bir kullanıcı tarafından erişilebilir olmadığından emin olmak için bir uygulamanın bir kullanıcının kimliğini doğrulaması önemlidir. Bu bölümde, bir GraphQL istemcisinin nasıl doğrulanacağını öğreneceğiz.
Ekspres JWT
Bu örnekte, bir istemci uygulaması oluşturmak için jQuery kullanacağız. İstekleri doğrulamak için kullanacağız express-jwt modül sunucu tarafında.
Express-jwt modülü, JWT belirteçlerini kullanarak HTTP isteklerini doğrulamanıza olanak tanıyan bir ara yazılımdır. JSON Web Token (JWT), oturum açmış kullanıcıyı tanımlayan uzun bir dizedir.
Kullanıcı başarıyla oturum açtığında, sunucu bir JWT belirteci oluşturur. Bu simge, bir günlüğü açıkça tanımlar. Başka bir deyişle, belirteç, kullanıcının kimliğinin bir temsilidir. Yani bir dahaki sefere, istemci sunucuya geldiğinde, gerekli kaynakları almak için bu belirteci sunması gerekir. İstemci bir mobil uygulama veya bir web uygulaması olabilir.
İllüstrasyon
Bu örneği anlamak için adım adım bir prosedür izleyeceğiz.
Sunucuyu Kurmak
Aşağıda sunucuyu kurma adımları verilmiştir -
Adım 1 - Proje için Gerekli Bağımlılıkları İndirin ve Yükleyin
Bir klasör oluşturun auth-server-app. Dizininizi şu şekilde değiştirin: auth-server-app terminalden. Ortam Kurulumu bölümünde açıklanan 3 ila 5 arasındaki adımları izleyin.
Adım 2 - Şema Oluşturun
Ekle schema.graphql proje klasöründeki dosya auth-server-app ve aşağıdaki kodu ekleyin -type Query
{
greetingWithAuth:String
}
3. Adım - Çözücü Ekleme
Bir dosya oluştur resolvers.js proje klasörüne ve aşağıdaki kodu ekleyin -
Çözümleyici, GraphQL'in bağlam nesnesinde kimliği doğrulanmış bir kullanıcı nesnesinin olup olmadığını doğrulayacaktır. Kimliği doğrulanmış bir kullanıcının mevcut olmaması bir istisna oluşturacaktır.
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}
Adım 4 - Server.js Dosyası Oluşturun
Kimlik doğrulama ara yazılımı, JSON Web Belirteci kullanarak arayanların kimliğini doğrular. Kimlik doğrulama URL'si http://localhost:9000/login.
Bu bir post operasyonudur. Kullanıcı, arka uçtan doğrulanacak olan e-postasını ve şifresini göndermelidir. Jwt.sign yöntemi kullanılarak geçerli bir belirteç oluşturulursa, istemcinin sonraki istekler için bunu başlıkta göndermesi gerekir.
Belirteç geçerliyse, req.user, yetkilendirme ve erişim kontrolü için daha sonraki ara yazılımlar tarafından kullanılmak üzere kodu çözülmüş JSON nesnesi ile ayarlanacaktır.
Aşağıdaki kod, istekleri doğrulamak için iki modül kullanır - jsonwebtoken ve express-jwt -
Kullanıcı, greetdüğmesi, / graphql yolu için bir istek yayınlanır. Kullanıcının kimliği doğrulanmamışsa, kendi kimliğini doğrulaması istenecektir.
Kullanıcıya e-posta kimliğini ve şifresini kabul eden bir form sunulur. Örneğimizde, kullanıcının kimliğinin doğrulanmasından / login yolu sorumludur.
/ Login yolu, kullanıcı tarafından sağlanan kimlik bilgileri için veritabanında bir eşleşme bulunup bulunmadığını doğrular.
Kimlik bilgileri geçersizse, kullanıcıya bir HTTP 401 istisnası döndürülür.
Kimlik bilgileri geçerliyse, sunucu tarafından bir belirteç oluşturulur. Bu simge, kullanıcıya yanıtın bir parçası olarak gönderilir. Bu, jwt.sign işlevi tarafından yapılır.
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});
});
Her istek için app.use () işlevi çağrılacaktır. Bu da expressJWT ara yazılımını çağıracaktır. Bu ara yazılım JSON Web Jetonunun kodunu çözecektir. Jetonda saklanan kullanıcı kimliği, talep nesnesinde bir özellik kullanıcısı olarak alınacak ve saklanacaktır.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Kullanıcı özelliğini GraphQL bağlamında kullanılabilir hale getirmek için, bu özellik context aşağıda gösterildiği gibi nesne -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Oluşturmak server.js geçerli klasör yolunda. Tam server.js dosyası aşağıdaki gibidir -
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}`));
Adım 5 - Uygulamayı Çalıştırın
Terminalde npm start komutunu yürütün . Sunucu, 9000 portunda çalışır durumda olacaktır. Burada, uygulamayı test etmek için istemci olarak GraphiQL kullanıyoruz.
Tarayıcıyı açın ve URL'yi yazın http://localhost:9000/graphiql. Düzenleyiciye aşağıdaki sorguyu yazın -
{
greetingWithAuth
}
Aşağıdaki yanıtta, kimliği doğrulanmış kullanıcı olmadığımız için bir hata aldık.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Bir sonraki bölümde, kimlik doğrulaması için bir istemci uygulaması oluşturalım.
JQuery İstemcisini Kurma
İstemci uygulamasında, şemayı çağıracak bir selamlama düğmesi sağlanmıştır. greetingWithAuth. Düğmeye giriş yapmadan tıklarsanız, size aşağıdaki hata mesajını verecektir -
Veritabanında bulunan bir kullanıcıyla oturum açtığınızda, aşağıdaki ekran görünecektir -
Erişmek için greeting, önce URL'ye erişmemiz gerekiyor http://localhost:9000/login aşağıdaki gibi rota.
Yanıt, sunucudan oluşturulan jetonu içerecektir.
$.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')
})
Başarılı bir giriş yaptıktan sonra, aşağıdaki gibi tebrikWithAuth şemasına erişebiliriz . Taşıyıcı jetonlu sonraki tüm istekler için bir Yetkilendirme başlığı olmalıdır.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Aşağıda index.html için kod verilmiştir -
<!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>