Skip to content

Commit

Permalink
feat: Adiciona autenticação
Browse files Browse the repository at this point in the history
  • Loading branch information
GoliasVictor committed Dec 19, 2024
1 parent 2f7fd5b commit 42385fe
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 36 deletions.
45 changes: 11 additions & 34 deletions src/LivrEtec.Front/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,19 @@
import { useEffect, useState } from 'react'
import './App.css'
import React from 'react'
import createClient, { Middleware } from "openapi-fetch";
import type { components, paths } from "./lib/api/v1";
type Livro = components["schemas"]["Livro"];
import { Route, Routes } from "react-router";
import { LoginPage } from './pages/loginPage';
import LivrosPage from './pages/livrosPage';
import { ProtectedLayout } from "./components/protectedLayout";

const accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIyIiwibmJmIjoxNzM0NTA1MDk1LCJleHAiOjE3MzQ1MjY2OTUsImlhdCI6MTczNDUwNTA5NX0.TQKUyTeCW2VKvguIVO53dUs3zGFLzIb8yfiIxCOX6Lg"

const authMiddleware: Middleware = {
async onRequest({ request }) {
request.headers.set("Authorization", `Bearer ${accessToken}`);
return request;
},
};

const client = createClient<paths>({ baseUrl: "http://localhost:5259" })
client.use(authMiddleware);

function App() {
const [todos, setTodos] = useState<Livro[]>([])
useEffect(() => {

client.GET("/livros").then(res => {
console.log(res.data);
if(res.data != null)
setTodos(res.data);

});

}, [])
return (
<>
{todos.map((t) =>
<React.Fragment key={t.id}>
<p>{ t.nome }</p>
</React.Fragment>
)}
</>
<Routes>
<Route element={<ProtectedLayout />}>
<Route path="/livros" element={<LivrosPage />}/>
</Route>
<Route path="/login" element={<LoginPage />}/>
</Routes>

)
}

Expand Down
21 changes: 21 additions & 0 deletions src/LivrEtec.Front/src/clientApi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import createClient, { Middleware } from "openapi-fetch";
import type { paths } from "./lib/api/v1";
import { useAuth } from "./hooks/useAuth";

export function useApi() {
const client = createClient<paths>({ baseUrl: import.meta.env.VITE_API_URL })

const { user } = useAuth()!
if (user) {
const accessToken = user.jwtToken
const authMiddleware: Middleware = {
async onRequest({ request }) {
request.headers.set("Authorization", `Bearer ${accessToken}`);
return request;
},
};
client.use(authMiddleware);
}

return client;
}
19 changes: 19 additions & 0 deletions src/LivrEtec.Front/src/components/protectedLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Outlet, Link } from "react-router";
import { useAuth } from "../hooks/useAuth";

export const ProtectedLayout = () => {
const { user } = useAuth()!;


if (!user) {
return <Link to="/login">
Não autenticado volte para o login
</Link>
}

return (<>
login: {user.user_login}<br/>
token: {user.jwtToken}
<Outlet />
</>)
};
46 changes: 46 additions & 0 deletions src/LivrEtec.Front/src/hooks/useAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// src/hooks/useAuth.jsx

import { createContext, useContext, useMemo, useState } from "react";
import { useNavigate } from "react-router";
import { useLocalStorage } from "./useLocalStorage";
const AuthContext = createContext<AuthContextData | null>(null);
type UserData = {
user_login: string ,
jwtToken: string
}
type AuthContextData = {
user : UserData | null
login: (data: UserData) => Promise<void>;
logout: () => void;
}
export const AuthProvider = ({ children }) => {

const [user, setUser] = useLocalStorage("user", null);
const navigate = useNavigate();

// call this function when you want to authenticate the user
const login = async (data : UserData) => {
setUser(data);
navigate("/login");
};

// call this function to sign out logged in user
const logout = () => {
setUser(null);
navigate("/login", { replace: true });
};

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

export const useAuth = () => {
return useContext(AuthContext);
};
28 changes: 28 additions & 0 deletions src/LivrEtec.Front/src/hooks/useLocalStorage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// src/hooks/useLocalStorage.jsx

import { useState } from "react";

export const useLocalStorage = (keyName, defaultValue) => {
const [storedValue, setStoredValue] = useState(() => {
try {
const value = window.localStorage.getItem(keyName);
if (value) {
return JSON.parse(value);
} else {
window.localStorage.setItem(keyName, JSON.stringify(defaultValue));
return defaultValue;
}
} catch (err) {
return defaultValue;
}
});
const setValue = (newValue) => {
try {
window.localStorage.setItem(keyName, JSON.stringify(newValue));
} catch (err) {
console.log(err);
}
setStoredValue(newValue);
};
return [storedValue, setValue];
};
9 changes: 7 additions & 2 deletions src/LivrEtec.Front/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from "react-router";
import './index.css'
import App from './App.tsx'

import { AuthProvider } from './hooks/useAuth.tsx';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>
</StrictMode>,
)
34 changes: 34 additions & 0 deletions src/LivrEtec.Front/src/pages/livrosPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect, useState } from 'react'
import '../App.css'
import React from 'react'
import type { components } from "./../lib/api/v1";
import { useApi } from './../clientApi';
type Livro = components["schemas"]["Livro"];


function LivrosPage() {
const [todos, setTodos] = useState<Livro[]>([])
const client = useApi()

useEffect(() => {

client.GET("/livros").then(res => {
console.log(res.data);
if(res.data != null)
setTodos(res.data);

});

}, [])
return (
<>
{todos.map((t) =>
<React.Fragment key={t.id}>
<p>{ t.nome }</p>
</React.Fragment>
)}
</>
)
}

export default LivrosPage
59 changes: 59 additions & 0 deletions src/LivrEtec.Front/src/pages/loginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import '../App.css'

import { useState } from "react";
import { useAuth } from "../hooks/useAuth";
import { useApi } from '../clientApi';
import axios from 'axios';
export const LoginPage = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const { login, logout, user } = useAuth()!;
const api = useApi();
const handleLogin = async (e) => {
e.preventDefault();


axios.post(import.meta.env.VITE_API_URL, {
hashSenha: password,
idUsuario: parseInt(username)
})
.then(async function({ data }) {
await login({
user_login: username,
jwtToken: data
});
})
.catch(function (error) {
console.log(error);
});


};
return (
<div>
{user?.user_login}
<form onSubmit={handleLogin}>
<div>
<label htmlFor="username">Username:</label>
<input
id="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label htmlFor="password">Password:</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">Login</button>
</form>
<button onClick={logout}>logout</button>
</div>
);
};

0 comments on commit 42385fe

Please sign in to comment.