Browse Source

token storage worker added

pull/24050/head
erdemcaygor 12 months ago
parent
commit
125537fd53
  1. 107
      npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts
  2. 55
      npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.ts

107
npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts

@ -1,3 +1,4 @@
// shared-worker-token-storage.service.ts
import { inject, Injectable } from '@angular/core';
import { OAuthStorage } from 'angular-oauth2-oidc';
import { AbpLocalStorageService } from '@abp/ng.core';
@ -6,34 +7,108 @@ import { AbpLocalStorageService } from '@abp/ng.core';
providedIn: 'root',
})
export class MemoryTokenStorageService implements OAuthStorage {
private keysShouldStoreInMemory = ['access_token', 'id_token', 'expires_at', 'id_token_claims_obj', 'id_token_expires_at', 'id_token_stored_at', 'access_token_stored_at', 'abpOAuthClientId', 'granted_scopes'];
private data = new Map<string, string>();
private keysShouldStoreInMemory = [
'access_token', 'id_token', 'expires_at',
'id_token_claims_obj', 'id_token_expires_at',
'id_token_stored_at', 'access_token_stored_at',
'abpOAuthClientId', 'granted_scopes'
];
private worker?: any;
private port?: MessagePort;
private cache = new Map<string, string>();
private localStorageService = inject(AbpLocalStorageService);
private useSharedWorker = false;
constructor() {
this.initializeStorage();
}
private initializeStorage(): void {
// @ts-ignore
if (typeof SharedWorker !== 'undefined') {
try {
// @ts-ignore
this.worker = new SharedWorker(
new URL('../workers/token-storage.worker.ts', import.meta.url),
{ type: 'module', name: 'oauth-token-storage' }
);
this.port = this.worker.port;
this.port.start();
this.useSharedWorker = true;
getItem(key: string): string {
if (this.keysShouldStoreInMemory.includes(key)) {
return this.data.get(key) || null;
this.port.onmessage = (event) => {
const { action, key, value } = event.data;
switch (action) {
case 'set':
this.cache.set(key, value);
break;
case 'remove':
this.cache.delete(key);
break;
case 'clear':
this.cache.clear();
break;
}
};
console.log('✅ Using SharedWorker for cross-tab token storage');
} catch (error) {
console.warn('⚠️ SharedWorker failed:', error);
this.useSharedWorker = false;
}
} else {
console.warn('⚠️ SharedWorker not supported');
this.useSharedWorker = false;
}
return this.localStorageService.getItem(key);
}
removeItem(key: string): void {
if (this.keysShouldStoreInMemory.includes(key)) {
this.data.delete(key);
getItem(key: string): string | null {
if (!this.keysShouldStoreInMemory.includes(key)) {
return this.localStorageService.getItem(key);
}
/* if (this.useSharedWorker) {
return this.cache.get(key) || null;
}*/
return this.cache.get(key) || null;
}
setItem(key: string, value: string): void {
if (!this.keysShouldStoreInMemory.includes(key)) {
this.localStorageService.setItem(key, value);
return;
}
this.localStorageService.removeItem(key);
if (this.useSharedWorker && this.port) {
// this.cache.set(key, value);
this.port.postMessage({ action: 'set', key, value });
} else {
this.cache.set(key, value);
}
}
setItem(key: string, data: string): void {
if (this.keysShouldStoreInMemory.includes(key)) {
this.data.set(key, data);
removeItem(key: string): void {
if (!this.keysShouldStoreInMemory.includes(key)) {
this.localStorageService.removeItem(key);
return;
}
this.localStorageService.setItem(key, data);
if (this.useSharedWorker && this.port) {
// this.cache.delete(key);
this.port.postMessage({ action: 'remove', key });
} else {
this.cache.delete(key);
}
}
clear() {
this.data.clear();
clear(): void {
if (this.useSharedWorker && this.port) {
this.port.postMessage({ action: 'clear' });
}
this.cache.clear();
}
}

55
npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.ts

@ -0,0 +1,55 @@
/// <reference no-default-lib="true"/>
/// <reference lib="es2020" />
/// <reference lib="webworker" />
declare const self: SharedWorkerGlobalScope;
interface TokenMessage {
action: 'set' | 'remove' | 'clear' | 'get';
key?: string;
value?: string;
}
const tokenStore = new Map<string, string>();
const ports = new Set<MessagePort>();
self.onconnect = (event: MessageEvent) => {
const port = event.ports[0];
ports.add(port);
port.onmessage = (e: MessageEvent<TokenMessage>) => {
const { action, key, value } = e.data;
switch (action) {
case 'set':
if (key && value !== undefined) {
tokenStore.set(key, value);
ports.forEach(p => p.postMessage({ action: 'set', key, value }));
}
break;
case 'remove':
if (key) {
tokenStore.delete(key);
ports.forEach(p => p.postMessage({ action: 'remove', key }));
}
break;
case 'clear':
tokenStore.clear();
ports.forEach(p => p.postMessage({ action: 'clear' }));
break;
case 'get':
if (key) {
const value = tokenStore.get(key) ?? null;
port.postMessage({ action: 'get', key, value });
}
break;
}
};
port.start();
tokenStore.forEach((value, key) => {
port.postMessage({ action: 'set', key, value });
});
};
export {};
Loading…
Cancel
Save