REFACTOR: Removido Mock e assegurado login com JWT
This commit is contained in:
parent
eb6e4faf2c
commit
04971ca82e
@ -6,6 +6,7 @@ import {
|
||||
startMicrosoftLogin,
|
||||
storeAuthSession,
|
||||
} from '../services/authService';
|
||||
import { isAuthenticated } from '../services/sessionService';
|
||||
|
||||
function decodeAuthPayload(payload) {
|
||||
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
|
||||
@ -21,10 +22,15 @@ export function useLogin() {
|
||||
const [providers, setProviders] = useState({ ldap: true, microsoft: false });
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.location.hash.includes('auth=') && isAuthenticated()) {
|
||||
navigate('/home', { replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
getAuthConfig()
|
||||
.then((config) => setProviders(config.providers || { ldap: true, microsoft: false }))
|
||||
.catch(() => setProviders({ ldap: true, microsoft: false }));
|
||||
}, []);
|
||||
}, [navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
const hashParams = new URLSearchParams(window.location.hash.replace(/^#/, ''));
|
||||
@ -38,23 +44,13 @@ export function useLogin() {
|
||||
return;
|
||||
} catch {
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
setError('Não foi possível concluir o login Microsoft.');
|
||||
setError('Nao foi possivel concluir o login Microsoft.');
|
||||
}
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const token = params.get('token');
|
||||
const rawUser = params.get('user');
|
||||
|
||||
if (!token || !rawUser) return;
|
||||
|
||||
try {
|
||||
const user = JSON.parse(rawUser);
|
||||
storeAuthSession({ token, user });
|
||||
if (window.location.search.includes('token=') || window.location.search.includes('user=')) {
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
navigate('/home', { replace: true });
|
||||
} catch {
|
||||
setError('Não foi possível concluir o login Microsoft.');
|
||||
setError('Fluxo de login expirado. Tente novamente.');
|
||||
}
|
||||
}, [navigate]);
|
||||
|
||||
|
||||
@ -30,6 +30,10 @@ export function startMicrosoftLogin() {
|
||||
}
|
||||
|
||||
export function storeAuthSession(authResult) {
|
||||
if (!authResult?.token || !authResult?.user) {
|
||||
throw new Error('Sessao de autenticacao invalida.');
|
||||
}
|
||||
|
||||
window.sessionStorage.setItem('authToken', authResult.token);
|
||||
window.sessionStorage.setItem('authUser', JSON.stringify(authResult.user));
|
||||
window.localStorage.removeItem('authToken');
|
||||
|
||||
@ -22,6 +22,33 @@ function readStoredUser() {
|
||||
}
|
||||
}
|
||||
|
||||
function decodeJwtPayload(token) {
|
||||
const [, payload] = String(token || '').split('.');
|
||||
|
||||
if (!payload) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
|
||||
const paddedBase64 = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
|
||||
|
||||
return JSON.parse(window.atob(paddedBase64));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function isTokenExpired(token) {
|
||||
const payload = decodeJwtPayload(token);
|
||||
|
||||
if (!payload?.exp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return payload.exp * 1000 <= Date.now();
|
||||
}
|
||||
|
||||
function normalizeProfile(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
@ -61,7 +88,14 @@ export function getCurrentUser() {
|
||||
}
|
||||
|
||||
export function getAuthToken() {
|
||||
return window.sessionStorage.getItem('authToken');
|
||||
const token = window.sessionStorage.getItem('authToken');
|
||||
|
||||
if (!token || isTokenExpired(token)) {
|
||||
clearSession();
|
||||
return null;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
export function isAuthenticated() {
|
||||
@ -70,7 +104,7 @@ export function isAuthenticated() {
|
||||
|
||||
export function getCurrentUserDisplay() {
|
||||
const user = getCurrentUser();
|
||||
const fullName = user?.name || user?.nome || user?.username || 'Ana Camolesi';
|
||||
const fullName = user?.name || user?.nome || user?.username || user?.email || 'Usuario';
|
||||
const nameParts = fullName.split(' ').filter(Boolean);
|
||||
const name =
|
||||
nameParts.length > 1 ? `${nameParts[0]} ${nameParts[nameParts.length - 1]}` : fullName;
|
||||
@ -94,7 +128,7 @@ export function getCurrentUserDisplay() {
|
||||
return {
|
||||
name,
|
||||
subtitle,
|
||||
initials: initials || 'AM',
|
||||
initials: initials || 'US',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import { isAuthenticated } from '../modules/auth/services/sessionService';
|
||||
import { getCurrentUserProfile, isAuthenticated } from '../modules/auth/services/sessionService';
|
||||
|
||||
export function ProtectedRoute({ children }) {
|
||||
export function ProtectedRoute({ children, allowedProfiles = [] }) {
|
||||
if (!isAuthenticated()) {
|
||||
return <Navigate to="/login" replace />;
|
||||
}
|
||||
|
||||
if (allowedProfiles.length && !allowedProfiles.includes(getCurrentUserProfile())) {
|
||||
return <Navigate to="/home" replace />;
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ import { AgentNewAttendancePage } from '../modules/attendance/pages/AgentNewAtte
|
||||
import { WhatsappAdminPage } from '../modules/management/pages/WhatsappAdminPage';
|
||||
import { ProtectedRoute } from './ProtectedRoute';
|
||||
|
||||
function privatePage(page) {
|
||||
return <ProtectedRoute>{page}</ProtectedRoute>;
|
||||
function privatePage(page, allowedProfiles = []) {
|
||||
return <ProtectedRoute allowedProfiles={allowedProfiles}>{page}</ProtectedRoute>;
|
||||
}
|
||||
|
||||
export const router = createBrowserRouter([
|
||||
@ -48,6 +48,6 @@ export const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: '/admin/whatsapp',
|
||||
element: privatePage(<WhatsappAdminPage />),
|
||||
element: privatePage(<WhatsappAdminPage />, ['admin']),
|
||||
},
|
||||
]);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { API_BASE_URL } from './apiConfig';
|
||||
import { clearSession } from '../../modules/auth/services/sessionService';
|
||||
|
||||
function getStoredToken() {
|
||||
return window.sessionStorage.getItem('authToken');
|
||||
@ -16,7 +17,7 @@ export function installAuthFetchInterceptor() {
|
||||
|
||||
const nativeFetch = window.fetch.bind(window);
|
||||
|
||||
window.fetch = (resource, options = {}) => {
|
||||
window.fetch = async (resource, options = {}) => {
|
||||
if (!shouldAttachToken(resource)) {
|
||||
return nativeFetch(resource, options);
|
||||
}
|
||||
@ -27,9 +28,19 @@ export function installAuthFetchInterceptor() {
|
||||
headers.set('Authorization', `Bearer ${getStoredToken()}`);
|
||||
}
|
||||
|
||||
return nativeFetch(resource, {
|
||||
const response = await nativeFetch(resource, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
|
||||
if (response.status === 401) {
|
||||
clearSession();
|
||||
|
||||
if (window.location.pathname !== '/login') {
|
||||
window.location.assign('/login');
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user