A GraphQL a hagyományos RESTful API architektúra népszerű alternatívája, rugalmas és hatékony adatlekérdezési és -manipulációs nyelvet kínál az API-khoz. Azzal együtt egyre fontosabbá válik a GraphQL API-k biztonságának prioritása az alkalmazások jogosulatlan hozzáféréssel és potenciális adatokkal szembeni védelme érdekében. jogsértéseket.
A GraphQL API-k védelmének egyik hatékony módja a JSON Web Tokens (JWT) megvalósítása. A JWT-k biztonságos és hatékony módszert biztosítanak a védett erőforrásokhoz való hozzáférés biztosítására és az engedélyezett műveletek végrehajtására, biztosítva a biztonságos kommunikációt az ügyfelek és az API-k között.
Hitelesítés és engedélyezés a GraphQL API-kban
nem úgy mint REST API-k, A GraphQL API-k általában egyetlen végponttal rendelkeznek, amely lehetővé teszi az ügyfelek számára, hogy dinamikusan lekérdezéseikben lekérdezzenek változó mennyiségű adatot. Noha ez a rugalmasság az erőssége, növeli a potenciális biztonsági támadások, például a hozzáférés-vezérlési sebezhetőségek kockázatát is.
Ennek a kockázatnak a csökkentése érdekében fontos robusztus hitelesítési és engedélyezési folyamatok megvalósítása, beleértve a hozzáférési engedélyek megfelelő meghatározását. Ezzel garantálja, hogy csak az arra jogosult felhasználók férhetnek hozzá a védett erőforrásokhoz, és végső soron csökkenti a potenciális biztonsági rések és adatvesztés kockázatát.
A projekt kódja megtalálható benne GitHub adattár.
Állítson be egy Express.js Apollo szervert
Apollo szerver egy széles körben használt GraphQL szerver implementáció a GraphQL API-khoz. Segítségével egyszerűen készíthet GraphQL-sémákat, definiálhat feloldókat, és kezelheti az API-k különböző adatforrásait.
Express.js Apollo szerver beállításához hozzon létre és nyisson meg egy projektmappát:
mkdir graphql-API-jwt
cd graphql-API-jwt
Ezután futtassa ezt a parancsot egy új Node.js projekt inicializálásához npm, a Node csomagkezelő:
npm init --yes
Most telepítse ezeket a csomagokat.
npm install apollo-server graphql mongoose jsonwebtokens dotenv
Végül hozzon létre a server.js fájlt a gyökérkönyvtárba, és állítsa be a szervert ezzel a kóddal:
const { ApolloServer } = require('apollo-server');
const mongoose = require('mongoose');
require('dotenv').config();const typeDefs = require("./graphql/typeDefs");
const resolvers = require("./graphql/resolvers");const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req }),
});const MONGO_URI = process.env.MONGO_URI;
mongoose
.connect(MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log("Connected to DB");
return server.listen({ port: 5000 });
})
.then((res) => {
console.log(`Server running at ${res.url}`);
})
.catch(err => {
console.log(err.message);
});
A GraphQL szerver a typeDefs és megoldók paramétereket, megadva az API által kezelhető sémát és műveleteket. A kontextus Az opció beállítja a req objektumot az egyes feloldók környezetéhez, ami lehetővé teszi a szerver számára, hogy hozzáférjen a kérésspecifikus részletekhez, például a fejlécértékekhez.
Hozzon létre egy MongoDB adatbázist
Az adatbázis-kapcsolat létrehozásához először hozzon létre egy MongoDB adatbázist vagy fürt létrehozása a MongoDB Atlason. Ezután másolja ki a megadott adatbázis-kapcsolat URI-karakterláncát, és hozzon létre a .env fájlt, és írja be a csatlakozási karakterláncot a következőképpen:
MONGO_URI=""
Határozza meg az adatmodellt
Határozzon meg egy adatmodellt a Mongoose segítségével. Újat csinálni model/user.js fájlt, és tartalmazza a következő kódot:
const {model, Schema} = require('mongoose');
const userSchema = new Schema({
name: String,
password: String,
role: String
});
module.exports = model('user', userSchema);
Határozza meg a GraphQL sémát
A GraphQL API-ban a séma meghatározza a lekérdezhető adatok szerkezetét, valamint felvázolja az elérhető műveletek (lekérdezések és mutációk), amelyeket végrehajthat az adatokkal való interakcióhoz a API.
A séma meghatározásához hozzon létre egy új mappát a projekt gyökérkönyvtárában, és nevezze el graphql. Adjon hozzá két fájlt ehhez a mappához: typeDefs.js és solvers.js.
Ban,-ben typeDefs.js fájl, tartalmazza a következő kódot:
const { gql } = require("apollo-server");
const typeDefs = gql`
type User {
id: ID!
name: String!
password: String!
role: String!
}
input UserInput {
name: String!
password: String!
role: String!
}
type TokenResult {
message: String
token: String
}
type Query {
users: [User]
}
type Mutation {
register(userInput: UserInput): User
login(name: String!, password: String!, role: String!): TokenResult
}
`;
module.exports = typeDefs;
Hozzon létre Rezolvereket a GraphQL API-hoz
A feloldófüggvények határozzák meg, hogy az ügyfél lekérdezéseire és mutációira, valamint a sémában meghatározott egyéb mezőkre hogyan lehet lekérni az adatokat. Amikor egy kliens lekérdezést vagy mutációt küld, a GraphQL szerver elindítja a megfelelő feloldókat, hogy feldolgozzák és visszaadják a szükséges adatokat különböző forrásokból, például adatbázisokból vagy API-kból.
A JSON webes tokenek (JWT-k) használatával történő hitelesítés és engedélyezés megvalósításához definiáljon feloldókat a regiszter- és bejelentkezési mutációkhoz. Ezek kezelik a felhasználói regisztrációs és hitelesítési folyamatokat. Ezután hozzon létre egy adatlekérési lekérdezés-feloldót, amely csak a hitelesített és jogosult felhasználók számára lesz elérhető.
Először azonban határozza meg a JWT-k generálásához és ellenőrzéséhez szükséges függvényeket. Ban,-ben solvers.js fájlt, kezdje a következő importálások hozzáadásával.
const User = require("../models/user");
const jwt = require('jsonwebtoken');
const secretKey = process.env.SECRET_KEY;
Ügyeljen arra, hogy az .env fájlhoz adja hozzá azt a titkos kulcsot, amelyet a JSON webes tokenek aláírásához használ.
SECRET_KEY = '' ;
Hitelesítési token létrehozásához használja a következő függvényt, amely egyedi attribútumokat is meghatároz a JWT tokenhez, például a lejárati időt. Ezenkívül más attribútumokat is beépíthet, például az adott alkalmazási követelmények alapján kiadott időben.
functiongenerateToken(user) {
const token = jwt.sign(
{ id: user.id, role: user.role },
secretKey,
{ expiresIn: '1h', algorithm: 'HS256' }
);
return token;
}
Most hajtsa végre a token-ellenőrzési logikát a következő HTTP-kérésekben szereplő JWT-jogkivonatok érvényesítéséhez.
functionverifyToken(token) {
if (!token) {
thrownewError('Token not provided');
}
try {
const decoded = jwt.verify(token, secretKey, { algorithms: ['HS256'] });
return decoded;
} catch (err) {
thrownewError('Invalid token');
}
}
Ez a függvény egy tokent vesz be bemenetként, ellenőrzi annak érvényességét a megadott titkos kulccsal, és visszaadja a dekódolt tokent, ha az érvényes, ellenkező esetben érvénytelen tokent jelez.
Határozza meg az API-feloldókat
A GraphQL API feloldóinak meghatározásához fel kell vázolnia azokat a konkrét műveleteket, amelyeket kezelni fog, ebben az esetben a felhasználói regisztrációs és bejelentkezési műveleteket. Először hozzon létre a megoldók objektumot, amely tartalmazza a feloldó függvényeket, majd határozza meg a következő mutációs műveleteket:
const resolvers = {
Mutation: {
register: async (_, { userInput: { name, password, role } }) => {
if (!name || !password || !role) {
thrownewError('Name password, and role required');
}const newUser = new User({
name: name,
password: password,
role: role,
});try {
const response = await newUser.save();return {
id: response._id,
...response._doc,
};
} catch (error) {
console.error(error);
thrownewError('Failed to create user');
}
},
login: async (_, { name, password }) => {
try {
const user = await User.findOne({ name: name });if (!user) {
thrownewError('User not found');
}if (password !== user.password) {
thrownewError('Incorrect password');
}const token = generateToken(user);
if (!token) {
thrownewError('Failed to generate token');
}
return {
message: 'Login successful',
token: token,
};
} catch (error) {
console.error(error);
thrownewError('Login failed');
}
}
},
A Regisztráció mutáció kezeli a regisztrációs folyamatot azáltal, hogy hozzáadja az új felhasználói adatokat az adatbázishoz. Amíg a Belépés A mutáció kezeli a felhasználói bejelentkezéseket – sikeres hitelesítés esetén JWT tokent generál, valamint sikerüzenetet küld a válaszban.
Most használja a lekérdezésfeloldót a felhasználói adatok lekéréséhez. Annak biztosítása érdekében, hogy ez a lekérdezés csak a hitelesített és jogosult felhasználók számára legyen elérhető, használjon engedélyezési logikát, amely csak azokra a felhasználókra korlátozza a hozzáférést, akik rendelkeznek Admin szerep.
Lényegében a lekérdezés először a token, majd a felhasználói szerepkör érvényességét ellenőrzi. Ha a jogosultságellenőrzés sikeres, a feloldó lekérdezés folytatja a felhasználók adatainak lekérését és visszaadását az adatbázisból.
Query: {
users: async (parent, args, context) => {
try {
const token = context.req.headers.authorization || '';
const decodedToken = verifyToken(token);if (decodedToken.role !== 'Admin') {
thrownew ('Unauthorized. Only Admins can access this data.');
}
const users = await User.find({}, { name: 1, _id: 1, role:1 });
return users;
} catch (error) {
console.error(error);
thrownewError('Failed to fetch users');
}
},
},
};
Végül indítsa el a fejlesztőkiszolgálót:
node server.js
Fantasztikus! Most menjen tovább, és tesztelje az API működését a böngésző Apollo Server API homokozójával. Használhatja például a Regisztráció mutáció új felhasználói adatok hozzáadásához az adatbázisban, majd a Belépés mutáció a felhasználó hitelesítéséhez.
Végül adja hozzá a JWT tokent az engedélyezési fejléchez, és folytassa az adatbázis felhasználói adatok lekérdezésével.
GraphQL API-k védelme
A hitelesítés és engedélyezés kulcsfontosságú összetevők a GraphQL API-k védelmében. Mindazonáltal fontos felismerni, hogy ezek önmagukban nem biztos, hogy elegendőek az átfogó biztonság biztosításához. További biztonsági intézkedéseket kell bevezetnie, például a bemeneti ellenőrzést és az érzékeny adatok titkosítását.
Átfogó biztonsági megközelítés alkalmazásával megvédheti API-it a különféle lehetséges támadások ellen.