No tienes acceso a esta clase

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

Aprende Ingl茅s, Programaci贸n, AI, Ciberseguridad y mucho m谩s.

Antes: $249

Currency
$209
Suscr铆bete

Termina en:

4 D铆as
16 Hrs
38 Min
21 Seg

Roles y permisos

14/30
Recursos

Aportes 33

Preguntas 0

Ordenar por:

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

隆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

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

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.!

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

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

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

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

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

Roles y permisos

.
La autenticaci贸n consiste en identificar personas, saber qui茅nes acceden a una aplicaci贸n. Mientras que la autorizaci贸n consiste en saber qu茅 permisos tiene cada persona que haya pasado por la autenticaci贸n.
.
Vamos a dar ciertos permisos a los usuarios para que puedan eliminar o editar un blog seg煤n el rol que tengan en la aplicaci贸n.
.
Lo primero que hacemos en el archivo auth.js es crear una lista de administradores. Al momento de loguear un usuario, revisaremos si el usuario es un administrador. Entonces, ademas del nombre de usuario tendremos tambi茅n una nueva propiedad llamada isAdmin que indica si se trata de un usuario administrador.
.

const adminList = ['Irisval', 'RetaxMaster', 'freddier'];

const AuthContext = React.createContext();

function AuthProvider({ children }) {
  ...
  const login = ({ username }) => {
    const isAdmin = adminList.find(admin => admin === username);
    setUser({ username, isAdmin });
    navigate('/profile');
  };
  ...
}

.
Posteriormente, desde BlogPost vamos a utilizar permisos para eliminar un blogpost. En primer lugar, hay 2 maneras para que alguien pueda eliminar un blogpost:
.

  • Un administrador puede eliminar cualquier blogpost.
  • Los usuarios pueden eliminar sus propios blogposts.

.
Por lo tanto, si se cumple alguna de estas condiciones, guardaremos el resultado en la variable canDelete, lo que indicar谩 si podemos renderizar un bot贸n para eliminar un blogpost.
.

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

  const auth = useAuth();

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

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

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

      {canDelete && (
        <button>Eliminar blogpost</button>
      )}
    </>
  );
}

export { BlogPost };
Ya no definir铆a si el usuario puede hacer tal acci贸n dentro de la app basado en isAdmin. Para ello generaria una estructura de roles donde se definan desde all铆 los permisos que aplican para cada uno de ellos, as铆 basado en el rol que tenga cada usuario ser谩 las acciones que tienen permitidas.

yo lo hice asi

Yo lo realice de la siguiente manera, me guie de unos de los post de los companeros y fui desarrollando mi idea, si tienen alguna sugerencia por favor me lo pueden comentar abajo. Como primera medida cree un archivo js para manejar los roles y la asignacion de estos en un objeto ![](https://static.platzi.com/media/user_upload/image-fa0083e1-80ae-4e66-9a6b-8b1f01ab6816.jpg) Despues realice el manejo del estado en el archivo auth dependiendo del rol que tenga cada usuario ![](https://static.platzi.com/media/user_upload/image-73dd3ce0-57e0-4928-beb7-23fce39ebfb4.jpg) Me tomo bastante tiempo encontrar esta solucion pero me siento satisfecho de como lo maneje. Gracias

Mi soluci贸n

En mi experiencia dise帽ando interfaces de administraci贸n puedo decir que normalmente la informaci贸n sobre el tipo de permisos que un usuario viene en un solo arreglo dentro de un json, no es recomendable ni practico crear listas separadas para administradores, autores o usuarios normales. Esto debido a que en cualquier tipo de iteraci贸n tendr铆amos que hacerlo sobre cada lista que tengamos, la cual va a variar seg煤n los tipos de permisos que nos soliciten afectando seriamente el performance de nuestra aplicaci贸n.
Siguiendo esta idea en auth.js cre茅 una lista mixta en donde pueden venir 3 tipos de roles:

  • admin
  • author
  • reader

auth.js

import React, { useContext } from "react";
import { Navigate, useNavigate } from "react-router-dom";

const AuthContext = React.createContext()
const users = [
    {
        username: 'Cortana',
        type: 'admin',
    },
    {
        username: 'Jhon117',
        type: 'admin',
    },
    {
        username: 'Nicobytes',
        type: 'author',
    },
    {
        username: 'diannerd',
        type: 'author',
    },
    {
        username: 'JuanDc',
        type: 'author',
    },
    {
        username: 'Mixtaco',
        type: 'reader',
    }
]

function AuthProvider({ children }){
    const navigate = useNavigate()

    const [user, setUser] = React.useState(null);

    const assignRole = username => {
        const userFound = users.filter( user => user.username === username )
        return userFound.length > 0 ? userFound[0].type : 'reader'
    }

    const login = ({ username }) => {
        const role = assignRole(username)
        
        setUser({ username, role })
        navigate('/profile')
    }

    const logout = () => {
        setUser(null)
        navigate('/')
    }

    const auth = { user, login, logout };
    
    return(
        <AuthContext.Provider value={auth}>
            { children }
        </AuthContext.Provider>
    )
}

function useAuth(){
    const auth = useContext(AuthContext);
    return auth;
}

function RedirectToLogin(props){
    const auth = useAuth();

    if (!auth.user) {
        return <Navigate to='/login' />;
    }

    return props.children;
}

export {
    AuthProvider,
    useAuth,
    RedirectToLogin
}

Ahora yo cambie la b煤squeda que el profe propone por una funci贸n llamada assignRole la cual retorna el nombre del tipo de permiso que le hemos asignado (Se supone que esta informaci贸n esta almacenada en una base de datos(DB) ). Como nuestra aplicaci贸n acepta cualquier nombre como autenticaci贸n en caso de no encontrarse en la DB, le asignamos permisos de solo lectura para evitar errores a futuro.
Ahora mi setUser actualiza pasando el username y rol independientemente de cual sea.

BlogPost.js

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

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

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

    const goToBack = () => {
        navigate(`/blog`);
    }

    return(
        <>
            <h2>
                { blogpost.title }
            </h2>
            <button onClick={goToBack}>
                Regresar
            </button>
            <p>
                { blogpost.content }
            </p>
            <p>
                { blogpost.author }
            </p>

            {(auth.user?.role === 'admin' || (auth.user?.role === 'author' && auth.user?.username === blogpost.author)) && (
                <button>
                    Eliminmar post
                </button>
            )}
            {(auth.user?.role === 'author' && auth.user?.username === blogpost.author) && (
                <button>
                    Editar post
                </button>
            )}
        </>
    )
}

Nos pasamos a BlogPost.js para hacer la comprobaci贸n y mostrar un bot贸n, para mostrarse debe cumplir con los siguientes puntos:

  1. Que tengamos un usuario autenticado.
  2. Que nuestro rol para eliminar sea 鈥渁dmin鈥 o 鈥渁uthor鈥.
  3. En caso de que tengamos permisos de author, nuestro usuario sea autor del post.

Nuestra comprobaci贸n queda algo larga, pero esto nos refuerza la seguridad, pues aunque nuestro usuario sea el autor del post debe tener permisos de edici贸n habilitados.
Esta l贸gica nos abre la puerta para agregar un bot贸n de edici贸n el cual ni siquiera los 鈥渁dmins鈥 pueden tener. Unicamente el autor del post puede tener este poder.
Esto nos abre la posibilidad de observar el tipo de usuario desde Profile.js y no andar haciendo console.logs para saber que tipo de usuario tenemos

Profile.js

import React from "react";
import { useAuth } from "./auth";

export default function ProfilePage(){
    const auth = useAuth()

    return(
        <>
           <h2>Profile</h2>
           <h3>
                {auth.user.username}
           </h3>
           <h4>
              Permisos:  {auth.user.role}
           </h4>
        </>
    );
}

Esta fue la mejor solucion que pude encontrar al reto
.
Inicialmente defini los valores de entrada. Con los diferentes array de roles, los junte en un unico array ya que me parecio la manera mas comoda de trabajar.

Luego, lo que hice fue crear una variable para saber quien es el usuario actual y verificar que exista en alguna de las listas.
.
Para ello utilice el metodo some para que recorriera el Array de arrays y dentro del mismo para cada Array busque aquel que con el metodo find contenga el usuario que se loggeo con el auth.
.
Asi pude sobreescribir la variable currentUser y con esta acceder usando la notacion de corchetes para poder usar una variable en el objeto skills que contiene los diferentes roles con su respectivo componente (en este caso estructura html) a renderizar deacuerdo a sus funciones


Finalmente use esa variable dentro de un div cualquiera en el componente BlogPost y de esta manera sea cual sea el rol se va a renderizar el componente asociado a este rol

C贸digo de la clase en TypeScript :

interface User {
    username: string,
    isAdmin: boolean,
}

interface Auth {
    user: User | null
    login: (value: Omit<User, "isAdmin">) => void
    logout: () => void
}

const adminList = ['Max', 'Tony', 'Steve'];

const AuthContext = createContext({} as Auth);

const AuthProvider: FC<PropsWithChildren> = ({ children }) => {

    const navigate = useNavigate();
    const [user, setUser] = useState<Auth['user']>(null);

    const login: Auth['login'] = ({ username }) => {
        const isAdmin = adminList.some(admin => admin === username);
        setUser({ username, isAdmin });
        navigate('/profile')
    }

    const logout: Auth['logout'] = () => {
        setUser(null);
        navigate('/');
    }

    const auth: Auth = { user, login, logout }

    return (
        <AuthContext.Provider value={auth}>
            {children}
        </AuthContext.Provider>
    )
}

BlogSpot:

type IBlogPostParams = {
    slug: string
}

const BlogPost = () => {

    const navigate = useNavigate();
    const { slug } = useParams<IBlogPostParams>();

    const { user } = useAuth();

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

    const canDelete = user?.isAdmin || blogpost?.author === user?.username;

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

    return(
        <>
            <h2>{ blogpost?.title }</h2>
            <button onClick={returnToBlog}>Volver al blog</button>
            <p>{ blogpost?.content }</p>
            <p>{ blogpost?.author }</p>

            {canDelete && (
                <button>Eliminar blogpost</button>
            )}
        </>
    )
}

Yo lo que hice fue crear:

const roles = [
    { role: adminList, permiso: true },
    { role: blogdata.author, permiso: true },
    { role: "editor", permiso: false },
];

tambien importe el archivo blogdata para tener los datos del autor

    const login = ({ username }) => {
        const isAdmin = adminList.find(admin => admin === username)
        const isRoles = roles.find(role => {
            if (role.role === username && role.permiso === true) {
                return true
            }
        })
        setUser({ username, isAdmin, isRoles });
        navigate('/profile')
    }

despues solamente cree una funcion nueva con un if.
en otro archivo a la variable canDelete le agregue:
auth.user?.isRoles y listo por ahora me funciona bien

Mi soluci贸n al reto fue crear un objeto permissions que ser谩 una propiedad m谩s del estado user que ya exist铆a en auth.js :

        const permissions = {
            create: false,
            edit: false,
            delete: false,
            approve: false,
            reject: false
        };

        if(isAdmin){
            permissions.create = true;
            permissions.edit = true;
            permissions.delete = true;                       
        }
        else if(isEditor)
        {
            permissions.create = true;
            permissions.edit = true;
        }
        else if(isApprover)
        {
            permissions.approve = true;
            permissions.reject = true;
        }     
        
        setUser({ userName, isAdmin, permissions });

En el componente BlogPost se realizan las validaciones contra permissions para definir si se puede editar, eliminar, aprobar o rechazar un determinado post:

    const statusIsUndefined = !blogPost.approved && !blogPost.rejected;    
    const canDelete = auth.user?.permissions?.delete && 
            (auth.user?.isAdmin || auth.user?.userName === blogPost.author) ;
    const canEdit = auth.user?.permissions?.edit && 
            (auth.user?.isAdmin || auth.user?.userName === blogPost.author) ;
    const canApprove = auth.user?.permissions?.approve && statusIsUndefined;
    const canReject = auth.user?.permissions?.reject && statusIsUndefined;

I N C R E I B L E

Como suele pasar, hay roles que tienen diferentes permisos, yo lo organic茅 de esta manera:

Creo que el poner false no es necesario, si no lo encuentres es false y si lo encuentra es true
lo hice pensando en como podr铆a estar organizado Platzi 馃挌

const estudiantes = {
  free: {
    cursos: {
      curos_free: true
    }
  },
  mensual: {
    cursos: {
      curos_free: true,
      curos_pago: true
    },
    certificado: true
  },
  anual: {
    cursos: {
      curos_free: true,
      curos_pago: true,
      eventos: true
    },
    certificado: true
  }
}

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 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
Ya lo habia implementado de antemano y lo que hago es que en la asignaci贸n de roles se de mediante nombre rol, lo que me permitiria que mediante el nombre digitado por el usuario si coincide con alguno de la lista le asigne su correspondiente rol o sino existe sea user, en el tema de definir si es admin, editor o lo que sea verifico el rol que ya le asignamos y si corresponde con la categoria buscada nos retornar铆a true, y ya en su uso llamo la funci贸n en donde si si es admin o los otros roles renderize X o Y informacion ![](https://static.platzi.com/media/user_upload/image-df6566c7-89c8-4d6d-9dc7-9138e2c01d82.jpg) ![](https://static.platzi.com/media/user_upload/image-91ceebef-2dfb-44f3-9307-f630d2fc8ff9.jpg)![](https://static.platzi.com/media/user_upload/image-6ef265cb-e69f-4d0a-82b2-558e768e2338.jpg)![](https://static.platzi.com/media/user_upload/image-701635a5-6ebe-40b0-942e-a7c663c2fc8b.jpg)
```js // Cambiar adminList por userdata const userdata = [ { username: 'Jose', accessLevel: 'user', }, { username: 'Iris', accessLevel: 'admin', }, { username: 'Retax', accessLevel: 'developer', }, { username: 'Juan', accessLevel: 'teacher', }, ]; //cambiar isAdmin por funcion function findAccessLevel (loginUsername) { let data = null userdata.forEach(element => { if (element.username === loginUsername) { data = element.accessLevel } }) return data } //Asignar distintos botones para cada tipo de usuario en BlogPost.js if (blogpost.author === auth.user?.username) { accessOptions.push('delete') accessOptions.push('edit') } else if (auth.user.accessLevel === 'admin'){ accessOptions.push('delete') } else if (auth.user.accessLevel === 'developer'){ accessOptions.push('change page layout') } else if (auth.user.accessLevel === 'teacher'){ accessOptions.push('report') accessOptions.push('reply') } else { accessOptions.push('report') } //Llamar en return return ( <> ... { accessOptions.map(text => ( <button>{text}</button> )) } ) ```No creo que sea el m茅todo m谩s 贸ptimo, pero ya ire pensando en cambiarlo si es necesario

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