Ajuda Autenticação/Login React, React Router
Salve galera, recentemente entrei em um projeto onde sou o único front-end, e tive que desenvolver uma aplicação com login, porém eu estou com dúvida sobre como realizei o login com React.
O código
O login é realizado mandando a requisição post com usuário e a senha para o servidor. Onde ele me devolve um JWT que salvo no localStorage
api.post( "/login",
{
username: username,
psswd: password,
})
.then((response) => {
if (response.data) {
localStorage.setItem("token",JSON.stringify(response.data));
return {success: true,message: "login realizado com sucesso"}
}
})
Ai criei uma PrivateRoute que valida se existe o token no localStorage ou redireciona a pessoa para o login.
const storageToken = JSON.parse(localStorage.getItem("token"));
if((storageToken && storageToken.token_type)){
return (<Outlet />)
} else {
return <Navigate to="/login" />
}
Para fazer as requisições no backend ele valida o token, porém ainda não foi me disponibilizado um endpoit para validar o meu token.
Além de validar o token no endpoit para acessar as rotas privadas(Não fiz pq ainda não está disponível o endpoint)
O que eu poderia melhorar?
Sem poder validar o token não haverá nenhuma rota privada. Nesse caso você apenas verifica se existe um token, isso significa que é possível injetar esse token no localstorage e pronto, a pessoa já tem acesso a rota privada sem autenticação.
Em questão de lógica, acredito que inverter as condicionais será mais vantajoso. Basicamente você tem apenas um caso onde o componente <Outlet />
será exibido, que é quando o usuário está devidamente autenticado. Invertendo as condicionais ficaria algo mais ou menos assim:
const storageToken = JSON.parse(localStorage.getItem("token"));
if(!storageToken || !storageToken.token_type)){
return (<Navigate to="/login" />)
}
// outras condições aqui
return <Outlet />
Dessa forma ficaria muito mais fácil para adicionar mais casos onde o usuário seria redirecionado para a página de login, inclusive evitando requisições desnecessárias para o backend.
Outra melhoria sutil seria utilizar async - await
ao invés de .then
com promisses. Por exemplo, a sua requisição post ficaria assim (estou assumindo que você está usando o axios):
// no axios um erro é retornado quando você recebe um código http de erro
try {
const { data } = await api.post("/login", {
username: username,
psswd: password,
})
localStorage.setItem("token", JSON.stringify(data))
return { success: true, message: "login realizado com sucesso" }
} catch (err) {
// trata o erro no login
return { success: false, message: "login não realizado" } // ou algo do tipo
}
Repare que, mesmo com o código ficando maior a leitura e o controle sobre ele são melhores com essa sintaxe. No caso de adicionar esse código dentro de um componente você o colocaria dentro de uma função assíncrona, que pode ser declarada dentro do próprio componente, daí sim utilizaria a sintaxe .then()
dentro do componente, mas agora apenas receberia o resultado do login, sem precisar se preocupar com a lógica da requisição.