All checks were successful
Build frontend / build (push) Successful in 53s
- AuthService: added cacheUser/getCachedUser methods - AuthService.getUser() prefers cached name over JWT claims - Login page: fetches full profile from API after login and caches it - Fixes navbar dropdown and homepage showing email instead of name
151 lines
3.6 KiB
JavaScript
151 lines
3.6 KiB
JavaScript
/**
|
|
* AuthService
|
|
* Manages authentication tokens and user role detection via JWT decoding.
|
|
*
|
|
* Roles (from JWT claims):
|
|
* - Owner: roles array contains "Owner"
|
|
* - Customer: authenticated but no "Owner" role
|
|
* - Guest: no token
|
|
*
|
|
* Methods:
|
|
* addToken(token) — store JWT token
|
|
* getToken() — retrieve JWT token
|
|
* deleteToken() — remove JWT token
|
|
* decodeToken() — decode JWT payload
|
|
* getUser() — get decoded user info
|
|
* getRoles() — get roles array from JWT
|
|
* isOwner() — check if user has Owner role
|
|
* isCustomer() — check if user is authenticated but not Owner
|
|
* isGuest() — check if no token exists
|
|
* isAuthenticated() — check if token exists
|
|
*/
|
|
|
|
const TOKEN_KEY = 'auth_token';
|
|
const USER_KEY = 'cached_user';
|
|
|
|
const AuthService = Object.freeze({
|
|
addToken(token) {
|
|
if (!token || typeof token !== 'string') return;
|
|
localStorage.setItem(TOKEN_KEY, token);
|
|
},
|
|
|
|
getToken() {
|
|
return localStorage.getItem(TOKEN_KEY);
|
|
},
|
|
|
|
deleteToken() {
|
|
localStorage.removeItem(TOKEN_KEY);
|
|
localStorage.removeItem(USER_KEY);
|
|
},
|
|
|
|
/**
|
|
* Cache full user profile (from API)
|
|
* @param {object} user — { name, email, phone, ... }
|
|
*/
|
|
cacheUser(user) {
|
|
if (!user) return;
|
|
localStorage.setItem(USER_KEY, JSON.stringify(user));
|
|
},
|
|
|
|
/**
|
|
* Get cached user profile
|
|
* @returns {object|null}
|
|
*/
|
|
getCachedUser() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem(USER_KEY));
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Decode JWT payload (base64)
|
|
* @returns {object|null}
|
|
*/
|
|
decodeToken() {
|
|
const token = this.getToken();
|
|
if (!token) return null;
|
|
try {
|
|
const payload = token.split('.')[1];
|
|
return JSON.parse(atob(payload));
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Extract user info from JWT
|
|
* @returns {object|null} — { id, name, email, phone, roles }
|
|
*/
|
|
getUser() {
|
|
const payload = this.decodeToken();
|
|
if (!payload) return null;
|
|
|
|
const cached = this.getCachedUser();
|
|
|
|
return {
|
|
id: payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || payload.sub || null,
|
|
name: cached?.name || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'] || null,
|
|
email: cached?.email || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'] || null,
|
|
phone: cached?.phone || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone'] || null,
|
|
roles: this.getRoles(),
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Get roles array from JWT
|
|
* @returns {string[]}
|
|
*/
|
|
getRoles() {
|
|
const payload = this.decodeToken();
|
|
if (!payload) return [];
|
|
const roles = payload['http://schemas.microsoft.com/ws/2008/06/identity/claims/role'];
|
|
if (Array.isArray(roles)) return roles;
|
|
if (typeof roles === 'string') return [roles];
|
|
return [];
|
|
},
|
|
|
|
/**
|
|
* User has Owner role
|
|
* @returns {boolean}
|
|
*/
|
|
isOwner() {
|
|
return this.getRoles().includes('Owner');
|
|
},
|
|
|
|
/**
|
|
* User has Admin role
|
|
* @returns {boolean}
|
|
*/
|
|
isAdmin() {
|
|
return this.getRoles().includes('Admin');
|
|
},
|
|
|
|
/**
|
|
* Authenticated user without Owner or Admin role (i.e. customer)
|
|
* @returns {boolean}
|
|
*/
|
|
isCustomer() {
|
|
return this.isAuthenticated() && !this.isOwner() && !this.isAdmin();
|
|
},
|
|
|
|
/**
|
|
* No token — guest user
|
|
* @returns {boolean}
|
|
*/
|
|
isGuest() {
|
|
return !this.getToken();
|
|
},
|
|
|
|
/**
|
|
* Token exists
|
|
* @returns {boolean}
|
|
*/
|
|
isAuthenticated() {
|
|
return !!this.getToken();
|
|
},
|
|
});
|
|
|
|
export default AuthService;
|