Bir giriş qapısı olan klubu təsəvvür edin. Mühafizəçi sənədinizi yoxlayır və qolunuza bilərzik taxır — bu autentifikasiyadır: «siz kimsiniz?». İçəridə hər otağın öz işçisi var: o, bilərziyə baxıb sizi buraxıb-buraxmamağa qərar verir — bu avtorizasiyadır: «sizə nə etmək olar?». REST-də «otaqlar» marşrutlardır və hər birini öz middleware-i bağlayır. GraphQL-də qapı birdir, /graphql, «otaqlar» isə sxemin sahələridir, ona görə yoxlamalar context-də və resolver-lərdə yaşayır. Bu dərsdə blog istifadəçini token ilə tanımağı öyrənəcək, başqalarının postlarını dəyişikliyə qarşı qoruyacağıq, GraphQL xətaları necə bildirir onu araşdıracağıq və serveri bahalı sorğulardan qoruyacağıq.
Bir qapı, çoxlu otaq
| Autentifikasiya | Avtorizasiya | |
|---|---|---|
| Sual | Siz kimsiniz? | Sizə nə etmək olar? |
| GraphQL-də harada | context: sorğu başına bir dəfə | resolver-lər: hər sahədə |
Müştəri JWT-ni Authorization: Bearer <token> başlığında göndərir (JWT-nin quruluşunu Node.js mövzusunda öyrənmisiniz; kitabxana eynidir — jose). Server tokeni istifadəçiyə və ya null-a çevirib context-ə qoyur, resolver-lər isə context.user-ə baxır.
Addım 1. Token veririk: login mutation-u
User modelinə passwordHash və role (Role enum-u: USER, ADMIN) əlavə edin və miqrasiyanı icra edin. Sxemdə login və me yaranır, authorId isə CreatePostInput-dan çıxır: «mən kiməm?» sualında müştərinin sözünə inanmaq olmaz, müəllif tokendən götürüləcək. email sahəsi ixtiyari olacaq — səbəbini aşağıda görəcəksiniz. Kitabxanaları quraşdırın: npm install jose bcrypt və npm install -D @types/bcrypt.
type User {
id: ID!
name: String!
email: String # optional on purpose, see below
posts: [Post!]!
}
input CreatePostInput {
title: String!
body: String!
published: Boolean = false # no authorId: the author is the logged-in user
}
input LoginInput { email: String!, password: String! }
type AuthPayload {
token: String
user: User
errors: [UserError!]!
}
type Query {
me: User # new, the other fields as before
}
type Mutation {
login(input: LoginInput!): AuthPayload # new
}tokens.ts tokenləri verir və yoxlayır — JWT mövzusundakı eyni SignJWT və jwtVerify; gizli açar .env-də saxlanılır:
// src/auth/tokens.ts
import { SignJWT, jwtVerify } from 'jose';
const key = new TextEncoder().encode(process.env.JWT_SECRET); // 32+ characters
export type AuthUser = { id: number; role: 'USER' | 'ADMIN' };
export function signToken(user: AuthUser): Promise<string> {
return new SignJWT({ role: user.role })
.setProtectedHeader({ alg: 'HS256' })
.setSubject(String(user.id))
.setExpirationTime('2h')
.sign(key);
}
export async function readUser(header?: string): Promise<AuthUser | null> {
if (!header?.startsWith('Bearer ')) return null;
try {
const { payload } = await jwtVerify(header.slice(7), key, {
algorithms: ['HS256'],
});
const id = Number(payload.sub);
if (!Number.isInteger(id)) return null;
return { id, role: payload.role === 'ADMIN' ? 'ADMIN' : 'USER' };
} catch {
return null; // expired, forged or broken: treat as anonymous
}
}