GraphQL - аутентификационный клиент
Аутентификация - это процесс или действие по проверке личности пользователя или процесса. Важно, чтобы приложение аутентифицировало пользователя, чтобы гарантировать, что данные не будут доступны анонимному пользователю. В этом разделе мы узнаем, как аутентифицировать клиента GraphQL.
Экспресс JWT
В этом примере мы будем использовать jQuery для создания клиентского приложения. Для аутентификации запросов мы будем использовать express-jwt модуль на стороне сервера.
Модуль express-jwt - это промежуточное ПО, которое позволяет аутентифицировать HTTP-запросы с помощью токенов JWT. Веб-токен JSON (JWT) - это длинная строка, которая идентифицирует вошедшего в систему пользователя.
После успешного входа пользователя в систему сервер генерирует токен JWT. Этот токен четко идентифицирует журнал. Другими словами, токен - это представление личности пользователя. Поэтому в следующий раз, когда клиент придет к серверу, он должен будет представить этот токен, чтобы получить необходимые ресурсы. Клиентом может быть мобильное приложение или веб-приложение.
Иллюстрация
Чтобы понять эту иллюстрацию, мы будем следовать пошаговой процедуре.
Настройка сервера
Ниже приведены шаги по настройке сервера -
Шаг 1 - Загрузите и установите необходимые зависимости для проекта
Создать папку auth-server-app. Измените свой каталог на auth-server-app с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».
Шаг 2 - Создайте схему
Добавить schema.graphql файл в папке проекта auth-server-app и добавьте следующий код -type Query
{
greetingWithAuth:String
}
Шаг 3 - Добавьте решатели
Создать файл resolvers.js в папке проекта и добавьте следующий код -
Сопоставитель проверит, доступен ли объект аутентифицированного пользователя в объекте контекста GraphQL. Это вызовет исключение, если аутентифицированный пользователь недоступен.
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}
Шаг 4 - Создайте файл Server.js
ПО промежуточного слоя аутентификации аутентифицирует вызывающих абонентов с помощью веб-токена JSON. URL для аутентификации http://localhost:9000/login.
Это почтовая операция. Пользователь должен отправить свой адрес электронной почты и пароль, который будет подтвержден серверной частью. Если действительный токен создается с использованием метода jwt.sign, клиент должен будет отправить его в заголовке для последующих запросов.
Если токен действителен, req.user будет установлен с объектом JSON, декодированным для использования последующим промежуточным программным обеспечением для авторизации и контроля доступа.
В следующем коде для аутентификации запросов используются два модуля - jsonwebtoken и express-jwt.
Когда пользователь нажимает на greetвыдается запрос на маршрут / graphql. Если пользователь не аутентифицирован, ему будет предложено пройти аутентификацию.
Пользователю предоставляется форма, которая принимает идентификатор электронной почты и пароль. В нашем примере за аутентификацию пользователя отвечает маршрут / login.
Маршрут / login проверяет, найдено ли совпадение в базе данных для учетных данных, предоставленных пользователем.
Если учетные данные недействительны, пользователю возвращается исключение HTTP 401.
Если учетные данные действительны, сервер генерирует токен. Этот токен отправляется как часть ответа пользователю. Это делает функция 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});
});
Для каждого запроса будет вызываться функция app.use (). Это, в свою очередь, вызовет промежуточное программное обеспечение expressJWT. Это промежуточное ПО будет декодировать веб-токен JSON. Идентификатор пользователя, хранящийся в токене, будет извлечен и сохранен как пользователь свойства в объекте запроса.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Чтобы сделать доступным свойство пользователя в контексте GraphQL, это свойство присваивается объекту context объект, как показано ниже -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Создайте server.js в текущем пути к папке. Полный файл server.js выглядит следующим образом:
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}`));
Шаг 5 - Запустите приложение
Выполните в терминале команду npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.
Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос -
{
greetingWithAuth
}
В ответе ниже мы получили сообщение об ошибке, так как мы не аутентифицированный пользователь.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
В следующем разделе давайте создадим клиентское приложение для аутентификации.
Настройка клиента JQuery
В клиентском приложении предусмотрена кнопка приветствия, которая будет вызывать схему. greetingWithAuth. Если вы нажмете кнопку без входа в систему, появится сообщение об ошибке, как показано ниже -
После входа в систему с пользователем, доступным в базе данных, появится следующий экран -
Чтобы получить доступ greeting, нам нужно сначала получить доступ к URL-адресу http://localhost:9000/login маршрут, как показано ниже.
Ответ будет содержать токен, сгенерированный сервером.
$.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')
})
После успешного входа в систему мы можем получить доступ к схеме приветствияWithAuth, как показано ниже. Для всех последующих запросов с токеном носителя должен быть заголовок авторизации.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Ниже приведен код для 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>