No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

5D
22H
0M
48S

Roles y permisos

14/30
Recursos

Aportes 19

Preguntas 0

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

隆Wohoo! Soy el admin 馃槑 jajaja. Para el caso del final yo crear铆a roles. Asignarle roles a cada usuario (ya no solo un campo de user.isAdmin, sino un campo user.role) y con base en ese campo validar cada acci贸n para saber si su rol le permite o no hacer X acci贸n :p

Roles y permisos

La autorizaci贸n es la que le permite a los usuarios tener cierto tipo de roles que nos permiten saber a que permisos tenemos acceso en nuestra aplicaci贸n, actualizar informaci贸n o borrarla, tener permisos solo de lectura de la informaci贸n, poder subir informaci贸n etc .

Podemos tener distintos tipos de roles, por mencionar algunos pueden ser el administrador, moderadores, usuarios premiun o freemiun y dem谩s.

Para empezar a implementar esta l贸gica de autorizaci贸n vamos a nuestro archivo auth.js:

// Listas de Autorizaci贸n
const adminList = [
  'RetaxMaster',
  'freddier',
  'juandc'
];

const AuthContext = React.createContext();

function AuthProvider({ children }) {
  /* Dentro de nuestra funci贸n de login veremos si el usuario a 
  ingresar es administrador */
  const login = ({ username }) => {
    /* Esta es la validaci贸n para saber si el usuario que ingresa a 
		la aplicaci贸n es administrador o no */
    const isAdmin = adminList.find(admin => admin === username);
    /* Ahora nuestros usuarios van a tener una propiedad para saber 
		si son admis */
    setUser({ username, isAdmin });
    navigate('/profile');
  }
}

Ahora en nuestra aplicaci贸n vamos a crear los permisos que van a tener nuestros administradores.

BlogPost.js

import { useAuth } from '../../auth/auth';

function BlogPost() {
	...	

  // Vamos a hacer uso de la autenticaci贸n
  const auth = useAuth();

	/* Aqui buscamos al momento de registrarnos si el usuario es parte 
  de la lista de administradores */
  const blogpost = blogdata.find( post => post.slug == slug );

  return (
    <>
      ...
      {/* Si nuestro usuario existe y es admin vamos a renderizar 
      este bot贸n */}
      {auth.user?.isAdmin && (
        <button>Eliminar blogpost</button>
      )} 
    </>
  );
}

Ahora si entramos a alguno de los BlogPost con el nombre de alg煤n administrador vamos a poder ver renderizado nuestro bot贸n de eliminar BloPost.

Ya tenemos la l贸gica para mostrar contenido dependiendo del rol.

Ahora si vemos los blogpost que tienen autores, digamos que el autor del blog desea eliminarlo, pero 驴como lo va a hacer?

Vamos a crear la l贸gica para que los autores del contenido puedan eliminar sus propios Blogs.

function BlogPost() {
  ...

  /* Aqu铆 validaremos si al acceder al blog soy el autor del blog y 
	pueda eliminarlo o tenga el rol de administrador para ello */
  const canDelete = auth.user?.isAdmin || blogpost.author === auth.user?.username;

  const returnToBlog = () => {
    navigate('/blog');
  }
  
  return (
    <>
      ...

      {/* Ahora vamos a preguntar si puedo borrar el BlogPost*/}
      {canDelete && (
        <button>Eliminar blogpost</button>
      )} 
    </>
  );
}

Ahora en caso de que seamos lo autores del Blog podemos eliminarlo, super f谩cil.

Pense que iba a ser complicado pero me resulto sencillo, cambiaria algunos nombres de los objetos.
Todavia tengo dudas de como se crean las API y los objetos JSON, si tienen una regla de planificar y organizar

const roles = {
    admin: {
        type: 'admin',
        read: true,
        write: true,
        delete: true
    },
    editor: {
        type: 'editor',
        read: true,
        write: true,
        delete: true
    },
    student: {
        type: 'student',
        write: false,
        read: true,
        delete: false
    },
}

const users = [{
    name: 'ivana',
    rol: roles.admin
},
{
    name: 'fred',
    rol: roles.admin
},
{
    name: 'cris',
    rol: roles.admin
},
{
    name: 'rocio',
    rol: roles.student
},
{
    name: 'leonel',
    rol: roles.editor
}]

const login = ({username}) => {
        const admin = users.filter(admin => admin.rol.type === 'admin')
        const isAdmin = admin.find(admin => admin.name === username)  . .. . . . .  }



//blogspot

    const canDelete = auth.user?.isAdmin || blogPost.author === auth.user?.username;

    // const filterA = auth.user?.admin?.filter( f => f.name && f.rol.delete)

    // console.log(filterA.find(f => auth.user?.username === f.name )) //devuelve un objeto con nombres de admin especificos

Reto

Mi soluci贸n al reto fue crear un arreglo de roles, con permisos anidados:

auth.js

const roles = [
  { role: "admin", update: true, delete: true },
  { role: "creator", update: true, delete: true },
  { role: "editor", update: true, delete: false },
];

Luego, crear una funci贸n para validad que el permiso que recibimos en la consulta existe:

function checkRoles(role) {
  return roles.find((item) => item.role === role);
}

Luego, crear un m茅todo que modifique el objecto user que se envia al provider:

function addPermissions(user) {
  if (!checkRoles(user.role)) return { ...user, update: false, delete: false };
  const role = roles.filter((item) => item.role === user.role);

  const newUser = { ...user, ...role[0] };
  return newUser;
}

Al crear hacer login quedar铆a as铆:

const login = ({ username }) => {

    let user = {
      username,
      isAdmin: false,
      role: "editor",
    };

    user = addPermissions(user);

    setUser(user);
    navigate("/profile");
  };

En componente de BlogPost solo debe de determinar que tipo de permisos tiene el usuario:
BlogPost.js

	const auth = useAuth();
	...
	{auth.user?.update && <button>Actualizar blogpost</button>}
	{auth.user?.delete && <button>Delete blogpost</button>}

Otra forma de saber si el usuario es admin:

const adminList = ["Irisval", "RetaxMaster", "freddier"]

const isAdmin = adminList.includes(username)

MDN - Array.prototype.includes

Les dejo un blogpost muy valioso donde explican un poco el tema de las rutas protegidas de una forma escalable. Espero les sirva como a mi 馃槈
https://www.robinwieruch.de/react-router-private-routes

Leyendo varios aportes mi soluci贸n fue de la siguiente manera:

en Auth.js crear una constante para los roles y sus permisos respectivos;
y despues un array de los usuarios registrados

const roles = {
  admin: {
    write: true,
    read: true,
    delete: true,
  },
  editor: {
    write: true,
    read: true,
    delete: false,
  },
  visitor: {
    write: false,
    read: true,
    delete: false,
  },
};

const users = [
  {
    name: "Andres",
    role: roles.admin,
  },
  {
    name: "Felipe",
    role: roles.editor,
  },
];

Dentro de AuthProvider asignar el usuario y su rol

function AuthProvider({ children }) {
//............
  const login = (username) => {
    //revisar si el usuario existe o lo crea como visitante
    const rol = users.find((usu) => usu.name === username);
    rol !== undefined
      ? setUser(rol)
      : setUser({ name: username, role: roles.visitor });
    navigate("/profile");
  };
 //............
}

finalmente en BlogPost.jsx hacer las validaciones para renderizar un boton o no
dependiendo de los permisos de su rol

return (
    <>
      <h2>{blog.title}</h2>
      <button onClick={handleBack}>Back</button>
      <p>{blog.author}</p>
      <p>{blog.content}</p>
      {user?.role.write && <button>Edit Post</button>}
      {user?.role.delete && <button>Delete Post</button>}
      {user?.name === blog.author && (
        <>
          <button>Edit Post</button>
          <button>Delete Post</button>
        </>
      )}
    </>
  );

Apoy谩ndome en los comentarios de los compa帽eros y lo aprendido en el curso, cree un array, que incluye a las personas autorizadas, los roles y permisos

const userType = [
    {
        name: ['Irisval', 'RetaxMaster', 'freddier'],
        role: 'admin',
        permissions: {
            create: true,
            read: true,
            update:false,
            delete: true,
        }
    },
    {
        name: ['yahe', 'pedro', 'pablo'],
        role: 'author',
        permissions: {
            create: true,
            read: true,
            update:true,
            delete: true,
        },

    },
];

Luego lo recorro para obtener las caracter铆sticas del usuario(esto en la funci贸n login):

 let role = []
    let permissions = {}
    let userRole = ''
    const isAuthorized = userType.some(user => user.name.includes(username))

    userType.forEach((user) => {
      if (user.name.includes(username) && isAuthorized) {
        role.push(user.role)
        userRole = role.join()
        permissions = { ...user.permissions }
      } else if (!user.name.includes(username) && !isAuthorized) {
        role = ['visitor']
        userRole = role.join()
        permissions = {
          write: false,
          read: true,
          update: false,
          delete: false,
        }
      }
    })

setUser({ username, isAuthorized, userRole, permissions });
    navigate('/profile');

En el blog, de acuerdo a los permisos que tiene cada rol, cree una condici贸n para que el administrador y el autor puedan borrar, pero solo el autor de cada blog, pueda editar

const postList = blogData.find(post => post.slug === slug)
   
 const canDelete = (auth.user?.isAuthorized && auth.user?.permissions.delete)&&
     (postList.author === auth.user?.username || auth.user.userRole === 'admin')

    const canUpdate = auth.user?.isAuthorized && auth.user?.permissions.update &&
    postList.author === auth.user?.username

El retorno quedar铆a as铆:

return (
        <>
          <h2>{postList.title}</h2>
          <button onClick={returnToBlog}>Volver al blog</button>
          <p>{postList.author}</p>
          <p>{postList.content}</p>
    
          {canDelete && (
            <button>Eliminar blogpost</button>
          )}

          {canUpdate && (
            <button>Editar blogpost</button>
          )}
        </>
      );

Inspirado en unos de los compa帽eros dejo una simple y humilde solucion.

En el primero array determinaremos los roles y lo que pueden hacer.
En el segundo crearemos usuarios con roles.

const roles = {
    admin: {
        type: 'admin',
        read: true,
        write: true,
        delete: true
    },
    editor: {
        type: 'editor',
        read: true,
        write: true,
        delete: false
    },
}

const users = [{
    name: 'ivana',
    rol: roles.admin
},
{
    name: 'fred',
    rol: roles.admin
},
{
    name: 'leonel',
    rol: roles.editor
}]

En la funcion de autenticacion de Loguin agregaremos una linea extra para extraer el rol.

  const login = ({ username }) => {
        const Isrol = users.find(user => (user.name === username) ? user.rol : null)
        setUser({ username, Isrol })
        navigator('/profile')
    }

y al final, en el blogPost veremos si tienen autorizacion o no.

const authorityDelet = auth.user?.Isrol?.rol.delete
    const authorityEdit = auth.user?.Isrol?.rol.write
    return (
        <>
            <h2> {post.title}</h2>
            <p>{post.content}</p>
            <button onClick={returnToBlog}>Volver un paso atras</button>
            {authorityEdit && (
                <button>Editar blog</button>
            )}
            {authorityDelet && (
                <button>Eliminar blog</button>
            )}
        </>
    )
}

Podria ser algo asi:

{
    admin: {
        create: true,
        view: true
        edit: true,
        delete: true
    },

    writter: {
        create: true,
        view: true,
        edit: true,
        delete: false
    },

    ...
}

Yo simplemente cree m谩s arrays e hice m谩s comprobaciones. Tiene m谩s sentido agregar una propiedad 鈥渞ole鈥 al user, pero ya que es un proyecto de prueba y que la l贸gica es casi la misma lo dej茅 as铆.

import React from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { blogData } from '../data/blogdata'
import { useAuth } from './auth'

export function BlogPost() {
    const navigate = useNavigate()
    const { slug } = useParams()
    const { user } = useAuth()

    const blogPost = blogData.find(post => post.slug === slug)
    const userIsAuthor = user?.username === blogPost.author
    const userIsEditor = user?.isEditor
    const userIsSpellChecker = user?.isSpellChecker
    const userIsModerator = user?.isModerator

    const returnToBlog = () => {
        navigate('/blog')
    }

    return (
        <>
            <button onClick={returnToBlog}>return to blog</button>
            <h2>{blogPost.title}</h2>
            <li>{blogPost.author}</li>
            <p>{blogPost.content}</p>

            {userIsModerator && <button>mark as best</button>}
            {(userIsModerator || userIsAuthor) && <button>delete blog</button>}
            {(userIsEditor || userIsAuthor) && <button>Modify blog</button>}
            {(userIsSpellChecker || userIsAuthor) && (
                <button>Correct spelling</button>
            )}
        </>
    )
}

Para el reto decidi crear un bot贸n editar el cual solo debe aparecer a usuarios administradores y editores sin embargo los editores no podr谩n ver el bot贸n eliminar post.

para ello la lista adminList la convert铆 en un array de objetos

const adminList = [
  { username: 'almendev', role: 'admin' },
  { username: 'juandc', role: 'editor' },
  { username: 'freddier', role: 'admin' }
]; 

ahora los usuarios tiene un rol que identificar al momento de renderizar ciertas funciones, ahora la funci贸n login queda de la siguiente manera

const login = ({ username }) => {
    const user = adminList.find(admin => admin.username === username) || { username: username, role: 'user' };
    setUser(user);
    navigate('/profile');
  };

de esta forma si el usuario esta dentro del array de usuarios con permisos especiales se retornada el objeto con su username y role sino se retornara un objeto que contiene los mismo campos sin embargo atribuye un rol por defecto llamado user por poner un nombre.

con esto hecho ya solo queda modificar el componente blogpost,
para lo cual ajuste el canDelete para que valide ahora el atributo role.

const canDelete = auth.user?.role === 'admin' || blogpost.author === auth.user?.username;

y para los editores agregue el siguiente condicional

{auth.user?.role === 'editor' && (
        <button>Editar</button>
      )}

si esta forma de hacerlo no es correcta me gustar铆a me ayuden con sus comentarios a mejorar.

Gracias

// Crear una lista nueva en auth.js
const editorList = ['Francisco', 'Javier', 'Luis'];
// Hacer la validaci贸n de su nombre y agregarlo al actualizador 
const isAdmin = adminList.find(admin => admin === username);
const isEditor = editorList.find(editor => editor === username);
setUser({ username, isAdmin, isEditor });

// Hacer la validaci贸n en BlogPost, creando una variable nueva
const canEdit = auth.user?.isEditor || blogpost.author === auth.user?.username;
// Crear un bot贸n nuevo, para editores.
{canEdit && (
        <button>Editar blogpost</button>
      )}

Esta es mi soluci贸n al reto de Juan:

separe la lista de personas y lo coloque en un archivo whiteList.js simplemente para tener un poco m谩s de orden

const whiteList = []

whiteList.push({
    name: 'eze',
    role: {
        admin: true,
        editor: true,
        QA: true,
        student: false,
    },
})


whiteList.push({
    name: 'agos',
    role: {
        admin: true,
        editor: true,
        QA: true,
        student: false,
    },
})


whiteList.push({
    name: 'nano',
    role: {
        admin: false,
        editor: true,
        QA: false,
        student: false,
    },
})


whiteList.push({
    name: 'erika',
    role: {
        admin: false,
        editor: true,
        QA: false,
        student: false,
    },
})

whiteList.push({
    name: 'marce',
    role: {
        admin: false,
        editor: false,
        QA: true,
        student: false,
    },
})


whiteList.push({
    name: 'alguien',
    role: {
        admin: false,
        editor: false,
        QA: true,
        student: false,
    },
})

whiteList.push({
    name: 'pepito',
    role: {
        admin: false,
        editor: false,
        QA: true,
        student: false,
    },
})

whiteList.push({
    name: 'otros',
    role: {
        admin: false,
        editor: false,
        QA: false,
        student: true,
    },
})

export { whiteList }

Luego, en nuestro archivo auth.js realice los siguientes cambios:

import { whiteList } from './whiteLIst'

const AuthContext = React.createContext()

function AuthProvider({ children }) {
    const navigate = useNavigate()
    const [user, setUser] = useState(null)


    const roleOf = (username) => {
        const user = whiteList.find(item => username === item.name )
        if (user) return user.role
        return {
            admin: false,
            editor: false,
            QA: false,
            student: true,
        }
    } 
    
    const login = ({ username }) => {
        const autorization = roleOf(username)
        setUser({ username, autorization })
        navigate('/profile')
    }

   ...
}

por 煤ltimo, en el archivo Blogpost.jsx hice las validaciones:

import React from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useAuth } from './auth';
import { blogData } from './blogData'

function BlogPost() {
    const navigate = useNavigate()
    const { slug } = useParams();
    const auth = useAuth()

    const blogpost = blogData.find( post => post.slug === slug );

    const isAdmin = auth.user.autorization.admin

    const isEditor = auth.user.autorization.editor || blogpost.author === auth.user?.username

    const isQA = auth.user.autorization.QA

    const isStudent = auth.user.autorization.student

    const returnToBlog = () => {
        navigate('/blog')
    }
    
    return (
    <>
        <h2>{blogpost.title}</h2>
        <button onClick={returnToBlog} >volver al blog</button>
        <p>{blogpost.author}</p>
        <p>{blogpost.content}</p>

        {(isAdmin || isEditor) && (
            <button>Eliminar blogpost</button>
        )}

        {(isAdmin || isQA) && (
            <button>El blog es correcto</button>
        )}

        {(isStudent) && (
            <button>Me gusta</button>
        )}
    </>
    );
}

export { BlogPost }

Esta fue la soluci贸n que se me ocurri贸, si se te ocurre algo mejor no dudes en dejarlo en los comentarios 馃槃

Yo lo que haria es que tendria un useState o un useReducer para cada role y dependiendo del rol se renderice una UI u otra

Para saber si un elemento existe en una lista podemos usar some de esta manera:

const isAdmin = adminList.some(admin => admin === username)

Para el reto podemos hacer asi:

// App.js

<Route path="/" element={<RequireAuth allowedRoles={['member', 'root']} />}>
	<Route index element={<Home />} />
	{/* Mis rutas */}
</Route>

// RequireAuth.js

const RequireAuth = ({ allowedRoles }) => {
  return isAuthenticated ? (
    <Layout>
       {
         allowedRoles.includes(roleUser) ? (
           <Outlet />
         ) : (
           <Navigate to="/unauthorized"  />
         )
        }
    </Layout>
    : (
      <Navigate to="/auth/login"  />
    )
}

export default RequireAuth

Yo era de esos men, que tuvo su propio servidor Habbo Hotel. Este curso me recuerda mucho cuando modificaba y otorgaba los permisos como due帽o de ese lugar.

Recuerdo que utilizaba PHP para quitar y poner.

!Ahhh, que recuerdos.!

Me pueden ayudar un poco, cuando me registro no sale el nombre del registrado xd

y tambi茅n cuando cierro sesi贸n no se quita el loguot :C
https://github.com/SRgenius1/Project-with-react-router/tree/main/components