Files
SweetHome/app/services/AuthService.js

163 lines
3.9 KiB
JavaScript
Raw Permalink Normal View History

/**
* 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(),
};
},
2026-04-17 14:40:47 +03:00
/**
* Get current authenticated user id
* @returns {number|string|null}
*/
getUserId() {
const user = this.getUser();
if (!user?.id) return null;
const parsedId = Number(user.id);
return Number.isFinite(parsedId) ? parsedId : user.id;
},
/**
* 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;