GraphQL on suosittu vaihtoehto perinteiselle RESTful API -arkkitehtuurille, joka tarjoaa joustavan ja tehokkaan datakyselyn ja manipulointikielen API: ille. Sen kanssa kasvavassa käytössä on entistä tärkeämpää priorisoida GraphQL-sovellusliittymien turvallisuus sovellusten suojaamiseksi luvattomalta käytöltä ja mahdollisilta tiedoilta. rikkomuksia.

Yksi tehokas tapa suojata GraphQL-sovellusliittymiä on ottaa käyttöön JSON Web Tokens (JWT). JWT: t tarjoavat turvallisen ja tehokkaan tavan myöntää pääsy suojattuihin resursseihin ja suorittaa valtuutettuja toimia, mikä varmistaa turvallisen viestinnän asiakkaiden ja API: iden välillä.

Todennus ja valtuutus GraphQL-sovellusliittymissä

Toisin kuin REST-sovellusliittymät, GraphQL-sovellusliittymillä on yleensä yksi päätepiste, jonka avulla asiakkaat voivat dynaamisesti pyytää vaihtelevia määriä tietoa kyselyissään. Vaikka tämä joustavuus on sen vahvuus, se lisää myös mahdollisten tietoturvahyökkäysten, kuten rikkoutuneiden kulunvalvontahaavoittuvuuksien, riskiä.

instagram viewer

Tämän riskin vähentämiseksi on tärkeää ottaa käyttöön vankat todennus- ja valtuutusprosessit, mukaan lukien käyttöoikeuksien oikea määrittely. Näin toimimalla takaat, että vain valtuutetut käyttäjät voivat käyttää suojattuja resursseja, ja viime kädessä vähennät mahdollisten tietoturvaloukkausten ja tietojen menetyksen riskiä.

Löydät tämän projektin koodin siitä GitHub arkisto.

Määritä Express.js Apollo -palvelin

Apollo palvelin on laajalti käytetty GraphQL-palvelintoteutus GraphQL API: ille. Sen avulla voit helposti rakentaa GraphQL-skeemoja, määrittää ratkaisejia ja hallita erilaisia ​​tietolähteitä sovellusliittymillesi.

Voit määrittää Express.js Apollo -palvelimen luomalla ja avaamalla projektikansion:

mkdir graphql-API-jwt
cd graphql-API-jwt

Suorita seuraavaksi tämä komento alustaaksesi uuden Node.js-projektin käyttämällä npm, Node-pakettien hallinta:

npm init --yes

Asenna nyt nämä paketit.

npm install apollo-server graphql mongoose jsonwebtokens dotenv

Luo lopuksi a server.js tiedosto juurihakemistoon ja määritä palvelimesi tällä koodilla:

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);
});

GraphQL-palvelin on määritetty typeDefs ja ratkaisijat parametrit, jotka määrittävät skeeman ja toiminnot, joita API voi käsitellä. The yhteydessä -vaihtoehto määrittää req-objektin kunkin ratkaisejan kontekstiin, jolloin palvelin voi käyttää pyyntökohtaisia ​​tietoja, kuten otsikkoarvoja.

Luo MongoDB-tietokanta

Luo ensin tietokantayhteys luo MongoDB-tietokanta tai perustaa klusterin MongoDB Atlasissa. Kopioi sitten toimitettu tietokantayhteyden URI-merkkijono ja luo a .env tiedosto ja kirjoita yhteysmerkkijono seuraavasti:

MONGO_URI=""

Määritä tietomalli

Määritä tietomalli käyttämällä Mongoosea. Luoda uusi mallit/user.js tiedosto ja sisällytä seuraava koodi:

const {model, Schema} = require('mongoose');

const userSchema = new Schema({
name: String,
password: String,
role: String
});

module.exports = model('user', userSchema);

Määritä GraphQL-skeema

GraphQL API: ssa skeema määrittelee kyselyn kohteena olevien tietojen rakenteen sekä hahmottelee käytettävissä olevat toiminnot (kyselyt ja mutaatiot), joita voit suorittaa vuorovaikutuksessa tietojen kanssa API.

Määritä skeema luomalla uusi kansio projektisi juurihakemistoon ja nimeämällä se graphql. Lisää tähän kansioon kaksi tiedostoa: typeDefs.js ja solvers.js.

Vuonna typeDefs.js tiedosto, sisällytä seuraava koodi:

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;

Luo Ratkaisuja GraphQL API: lle

Resolver-funktiot määrittävät, kuinka tiedot noudetaan vastauksena asiakkaan kyselyihin ja mutaatioihin sekä muihin skeemassa määriteltyihin kenttiin. Kun asiakas lähettää kyselyn tai mutaation, GraphQL-palvelin laukaisee vastaavat ratkaisijat käsittelemään ja palauttamaan vaaditut tiedot eri lähteistä, kuten tietokannoista tai API: ista.

Todennuksen ja valtuutuksen toteuttamiseksi JSON Web Tokens (JWT: t) avulla määritä rekisterin ja kirjautumismutaatioiden ratkaisijat. Nämä käsittelevät käyttäjien rekisteröinti- ja todennusprosessit. Luo sitten tiedonhakukyselyn ratkaisija, joka on vain todennettujen ja valtuutettujen käyttäjien käytettävissä.

Mutta ensin määritä toiminnot JWT: iden luomiseksi ja tarkistamiseksi. Vuonna solvers.js tiedosto, aloita lisäämällä seuraavat tuonnit.

const User = require("../models/user");
const jwt = require('jsonwebtoken');
const secretKey = process.env.SECRET_KEY;

Muista lisätä .env-tiedostoon salainen avain, jota käytät JSON-verkkotunnusten allekirjoittamiseen.

SECRET_KEY = '';

Luodaksesi todennustunnuksen, sisällytä seuraava toiminto, joka määrittää myös yksilölliset attribuutit JWT-tunnukselle, esimerkiksi vanhenemisajan. Lisäksi voit sisällyttää muita attribuutteja, kuten myönnetty ajoissa erityisten sovellusvaatimustesi perusteella.

functiongenerateToken(user) {
const token = jwt.sign(
{ id: user.id, role: user.role },
secretKey,
{ expiresIn: '1h', algorithm: 'HS256' }
 );

return token;
}

Ota nyt käyttöön tunnuksen vahvistuslogiikka myöhempien HTTP-pyyntöjen sisältämien JWT-tunnusten vahvistamiseksi.

functionverifyToken(token) {
if (!token) {
thrownewError('Token not provided');
}

try {
const decoded = jwt.verify(token, secretKey, { algorithms: ['HS256'] });
return decoded;
} catch (err) {
thrownewError('Invalid token');
}
}

Tämä toiminto ottaa tunnuksen syötteeksi, tarkistaa sen kelpoisuuden käyttämällä määritettyä salaista avainta ja palauttaa dekoodatun tunnuksen, jos se on kelvollinen, muuten antaa virheilmoituksen, joka osoittaa virheellisen tunnuksen.

Määritä API-ratkaisut

Määrittääksesi GraphQL API: n ratkaisijat, sinun on hahmoteltava tietyt toiminnot, joita se hallitsee, tässä tapauksessa käyttäjän rekisteröinti- ja sisäänkirjautumistoiminnot. Luo ensin a ratkaisijat objekti, joka sisältää ratkaisijafunktiot, määritä sitten seuraavat mutaatiotoiminnot:

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');
}
}
},

The rekisteröidy mutaatio hoitaa rekisteröintiprosessin lisäämällä uudet käyttäjätiedot tietokantaan. Samalla kun Kirjaudu sisään mutaatio hallitsee käyttäjien kirjautumisia – onnistuneen todennuksen yhteydessä se luo JWT-tunnuksen ja palauttaa vastauksessa onnistumisviestin.

Ota nyt mukaan kyselyn ratkaisija käyttäjätietojen hakemista varten. Varmistaaksesi, että tämä kysely on vain todennettujen ja valtuutettujen käyttäjien käytettävissä, sisällytä valtuutuslogiikka rajoittamaan pääsy vain käyttäjiin, joilla on Admin rooli.

Pohjimmiltaan kysely tarkistaa ensin tunnuksen ja sitten käyttäjän roolin. Jos valtuutustarkistus onnistuu, ratkaisijakysely jatkaa käyttäjien tietojen hakemista ja palauttamista tietokannasta.

 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');
}
},
},
};

Käynnistä lopuksi kehityspalvelin:

node server.js

Mahtava! Mene nyt eteenpäin ja testaa API: n toimivuutta selaimesi Apollo Server API -hiekkalaatikon avulla. Voit käyttää esimerkiksi rekisteröidy mutaatio, joka lisää uusia käyttäjätietoja tietokantaan, ja sitten Kirjaudu sisään mutaatio käyttäjän todentamiseksi.

Lisää lopuksi JWT-tunnus valtuutusotsikko-osioon ja jatka käyttäjätietojen kyselyä tietokannasta.

GraphQL-sovellusliittymien suojaaminen

Todennus ja valtuutus ovat tärkeitä osia GraphQL-sovellusliittymien suojaamisessa. On kuitenkin tärkeää tunnustaa, että ne eivät välttämättä yksin riitä takaamaan kattavaa turvallisuutta. Sinun tulee ottaa käyttöön lisäturvatoimenpiteitä, kuten syötteiden validointi ja arkaluonteisten tietojen salaus.

Ottamalla käyttöön kattavan tietoturvalähestymistavan voit suojata API-liittymiäsi erilaisilta mahdollisilta hyökkäyksiltä.