En aquest tema, explorarem com implementar l'autenticació i l'autorització en un servidor GraphQL. Aquests dos conceptes són fonamentals per assegurar que només els usuaris autoritzats puguin accedir a les dades i funcionalitats de la teva aplicació.

Continguts

  1. Introducció a l'autenticació i autorització
  2. Implementació de l'autenticació
  3. Implementació de l'autorització
  4. Exemples pràctics
  5. Exercicis pràctics

  1. Introducció a l'autenticació i autorització

Autenticació

L'autenticació és el procés de verificar la identitat d'un usuari. Això es fa normalment mitjançant credencials com ara noms d'usuari i contrasenyes, tokens JWT (JSON Web Tokens), o OAuth.

Autorització

L'autorització és el procés de determinar si un usuari autenticat té permís per accedir a un recurs o realitzar una acció específica. Això es fa normalment mitjançant rols i permisos.

  1. Implementació de l'autenticació

Utilitzant JWT per a l'autenticació

  1. Instal·lació de dependències

    npm install jsonwebtoken bcryptjs
    
  2. Creació de tokens JWT

    const jwt = require('jsonwebtoken');
    const bcrypt = require('bcryptjs');
    
    const SECRET_KEY = 'your_secret_key';
    
    // Funció per generar un token JWT
    function generateToken(user) {
      return jwt.sign({ id: user.id, email: user.email }, SECRET_KEY, { expiresIn: '1h' });
    }
    
    // Funció per verificar un token JWT
    function verifyToken(token) {
      try {
        return jwt.verify(token, SECRET_KEY);
      } catch (error) {
        throw new Error('Invalid token');
      }
    }
    
  3. Autenticació d'usuaris

    const users = []; // Simulació d'una base de dades d'usuaris
    
    async function login(email, password) {
      const user = users.find(user => user.email === email);
      if (!user) {
        throw new Error('User not found');
      }
    
      const isPasswordValid = await bcrypt.compare(password, user.password);
      if (!isPasswordValid) {
        throw new Error('Invalid password');
      }
    
      return generateToken(user);
    }
    
    async function register(email, password) {
      const hashedPassword = await bcrypt.hash(password, 10);
      const newUser = { id: users.length + 1, email, password: hashedPassword };
      users.push(newUser);
      return generateToken(newUser);
    }
    

  1. Implementació de l'autorització

Utilitzant rols i permisos

  1. Definició de rols i permisos

    const roles = {
      ADMIN: 'ADMIN',
      USER: 'USER'
    };
    
    const permissions = {
      READ: 'READ',
      WRITE: 'WRITE'
    };
    
    const rolePermissions = {
      [roles.ADMIN]: [permissions.READ, permissions.WRITE],
      [roles.USER]: [permissions.READ]
    };
    
  2. Verificació de permisos

    function checkPermission(user, permission) {
      const userPermissions = rolePermissions[user.role];
      if (!userPermissions.includes(permission)) {
        throw new Error('Permission denied');
      }
    }
    
  3. Integració amb resolvers de GraphQL

    const resolvers = {
      Query: {
        getUser: (parent, args, context) => {
          const user = verifyToken(context.token);
          checkPermission(user, permissions.READ);
          return users.find(u => u.id === args.id);
        }
      },
      Mutation: {
        createUser: (parent, args, context) => {
          const user = verifyToken(context.token);
          checkPermission(user, permissions.WRITE);
          return register(args.email, args.password);
        }
      }
    };
    

  1. Exemples pràctics

Exemple de resolució d'una consulta amb autenticació i autorització

const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type User {
    id: ID!
    email: String!
  }

  type Query {
    getUser(id: ID!): User
  }

  type Mutation {
    login(email: String!, password: String!): String
    register(email: String!, password: String!): String
  }
`;

const resolvers = {
  Query: {
    getUser: (parent, args, context) => {
      const user = verifyToken(context.token);
      checkPermission(user, permissions.READ);
      return users.find(u => u.id === args.id);
    }
  },
  Mutation: {
    login: async (parent, args) => {
      return await login(args.email, args.password);
    },
    register: async (parent, args) => {
      return await register(args.email, args.password);
    }
  }
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => {
    const token = req.headers.authorization || '';
    return { token };
  }
});

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});

  1. Exercicis pràctics

Exercici 1: Implementar autenticació amb JWT

  1. Crea una funció per generar tokens JWT.
  2. Crea una funció per verificar tokens JWT.
  3. Implementa la funció de registre d'usuaris amb hash de contrasenya.

Exercici 2: Implementar autorització basada en rols

  1. Defineix rols i permisos.
  2. Crea una funció per verificar permisos.
  3. Integra la verificació de permisos en els resolvers de GraphQL.

Solucions

Solució Exercici 1

// Funció per generar un token JWT
function generateToken(user) {
  return jwt.sign({ id: user.id, email: user.email }, SECRET_KEY, { expiresIn: '1h' });
}

// Funció per verificar un token JWT
function verifyToken(token) {
  try {
    return jwt.verify(token, SECRET_KEY);
  } catch (error) {
    throw new Error('Invalid token');
  }
}

// Funció de registre d'usuaris
async function register(email, password) {
  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { id: users.length + 1, email, password: hashedPassword };
  users.push(newUser);
  return generateToken(newUser);
}

Solució Exercici 2

// Definició de rols i permisos
const roles = {
  ADMIN: 'ADMIN',
  USER: 'USER'
};

const permissions = {
  READ: 'READ',
  WRITE: 'WRITE'
};

const rolePermissions = {
  [roles.ADMIN]: [permissions.READ, permissions.WRITE],
  [roles.USER]: [permissions.READ]
};

// Funció per verificar permisos
function checkPermission(user, permission) {
  const userPermissions = rolePermissions[user.role];
  if (!userPermissions.includes(permission)) {
    throw new Error('Permission denied');
  }
}

// Integració amb resolvers de GraphQL
const resolvers = {
  Query: {
    getUser: (parent, args, context) => {
      const user = verifyToken(context.token);
      checkPermission(user, permissions.READ);
      return users.find(u => u.id === args.id);
    }
  },
  Mutation: {
    createUser: (parent, args, context) => {
      const user = verifyToken(context.token);
      checkPermission(user, permissions.WRITE);
      return register(args.email, args.password);
    }
  }
};

Conclusió

En aquesta secció, hem après com implementar l'autenticació i l'autorització en un servidor GraphQL utilitzant JWT per a l'autenticació i rols i permisos per a l'autorització. Hem vist exemples pràctics i hem realitzat exercicis per reforçar els conceptes apresos. Amb aquests coneixements, estàs preparat per assegurar la teva aplicació GraphQL i protegir les teves dades de manera efectiva.

© Copyright 2024. Tots els drets reservats