Browse Source

feat: create auth-error-filter and include filters to oauth error listener

* Create abstarct-auth-filter
* Create auth-events model
* Create oauth-error-filter.service
pull/18577/head
masumulu28 3 years ago
parent
commit
65b03e63f7
  1. 5
      npm/ng-packs/packages/core/package.json
  2. 34
      npm/ng-packs/packages/core/src/lib/abstracts/auth-error-filter.ts
  3. 3
      npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts
  4. 1
      npm/ng-packs/packages/core/src/lib/abstracts/index.ts
  5. 4
      npm/ng-packs/packages/core/src/lib/core.module.ts
  6. 60
      npm/ng-packs/packages/core/src/lib/models/auth-events.ts
  7. 11
      npm/ng-packs/packages/core/src/lib/models/auth.ts
  8. 1
      npm/ng-packs/packages/core/src/lib/models/index.ts
  9. 6
      npm/ng-packs/packages/oauth/package.json
  10. 6
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  11. 1
      npm/ng-packs/packages/oauth/src/lib/services/index.ts
  12. 46
      npm/ng-packs/packages/oauth/src/lib/services/oauth-error-filter.service.ts
  13. 6
      npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts
  14. 21
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts

5
npm/ng-packs/packages/core/package.json

@ -8,9 +8,8 @@
},
"dependencies": {
"@abp/utils": "~7.4.4",
"angular-oauth2-oidc": "^15.0.1",
"just-clone": "^6.1.1",
"just-compare": "^2.3.0",
"just-clone": "^6.0.0",
"just-compare": "^2.0.0",
"ts-toolbelt": "6.15.4",
"tslib": "^2.0.0"
},

34
npm/ng-packs/packages/core/src/lib/abstracts/auth-error-filter.ts

@ -0,0 +1,34 @@
import { Signal, signal } from '@angular/core';
import { AuthErrorEvent, AuthErrorFilter } from '../models';
export abstract class AbstractAuthErrorFilter<T, E> {
readonly #filters = signal<Array<T>>([]);
filters = this.#filters.asReadonly();
abstract get(id: string): T;
abstract add(filter: T): void;
abstract patch(item: Partial<T>): void;
abstract remove(id: string): void;
abstract run(event: E): boolean;
}
export class AuthErrorFilterService<
T = AuthErrorEvent,
E = AuthErrorFilter,
> extends AbstractAuthErrorFilter<T, E> {
get(id: string): T {
throw new Error('Import AbpOAuthModule from @abp/ng.oauth or custom implementation');
}
add(filter: T): void {
throw new Error('Import AbpOAuthModule from @abp/ng.oauth or custom implementation');
}
patch(item: Partial<T>): void {
throw new Error('Import AbpOAuthModule from @abp/ng.oauth or custom implementation');
}
remove(id: string): void {
throw new Error('Import AbpOAuthModule from @abp/ng.oauth or custom implementation');
}
run(event: E): boolean {
throw new Error('Import AbpOAuthModule from @abp/ng.oauth or custom implementation');
}
}

3
npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts

@ -33,9 +33,8 @@ export class AuthService implements IAuthService {
navigateToLogin(queryParams?: Params): void {}
get isInternalAuth() {
get isInternalAuth(): boolean {
throw new Error('not implemented');
return false;
}
get isAuthenticated(): boolean {

1
npm/ng-packs/packages/core/src/lib/abstracts/index.ts

@ -3,3 +3,4 @@ export * from './ng-model.component';
export * from './auth.guard';
export * from './auth.service';
export * from './auth-response.model';
export * from './auth-error-filter';

4
npm/ng-packs/packages/core/src/lib/core.module.ts

@ -39,6 +39,7 @@ import { QUEUE_MANAGER } from './tokens/queue.token';
import { DefaultQueueManager } from './utils/queue';
import { IncludeLocalizationResourcesProvider } from './providers/include-localization-resources.provider';
import { SORT_COMPARE_FUNC, compareFuncFactory } from './tokens/compare-func.token';
import { AuthErrorFilterService } from './abstracts';
/**
* BaseCoreModule is the module that holds
@ -179,7 +180,7 @@ export class CoreModule {
},
{
provide: SORT_COMPARE_FUNC,
useFactory: compareFuncFactory
useFactory: compareFuncFactory,
},
{
provide: QUEUE_MANAGER,
@ -189,6 +190,7 @@ export class CoreModule {
provide: OTHERS_GROUP,
useValue: options.othersGroup || 'AbpUi::OthersGroup',
},
AuthErrorFilterService,
IncludeLocalizationResourcesProvider,
],
};

60
npm/ng-packs/packages/core/src/lib/models/auth-events.ts

@ -0,0 +1,60 @@
export type EventType =
| 'discovery_document_loaded'
| 'jwks_load_error'
| 'invalid_nonce_in_state'
| 'discovery_document_load_error'
| 'discovery_document_validation_error'
| 'user_profile_loaded'
| 'user_profile_load_error'
| 'token_received'
| 'token_error'
| 'code_error'
| 'token_refreshed'
| 'token_refresh_error'
| 'silent_refresh_error'
| 'silently_refreshed'
| 'silent_refresh_timeout'
| 'token_validation_error'
| 'token_expires'
| 'session_changed'
| 'session_error'
| 'session_terminated'
| 'session_unchanged'
| 'logout'
| 'popup_closed'
| 'popup_blocked'
| 'token_revoke_error';
export abstract class AuthEvent {
readonly type: EventType;
constructor(type: EventType) {
this.type = type;
}
}
export class AuthSuccessEvent extends AuthEvent {
readonly info: any;
constructor(type: EventType, info?: any) {
super(type);
this.info = info;
}
}
export class AuthInfoEvent extends AuthEvent {
readonly info: any;
constructor(type: EventType, info?: any) {
super(type);
this.info = info;
}
}
export class AuthErrorEvent extends AuthEvent {
readonly reason: object;
readonly params: object;
constructor(type: EventType, reason: object, params?: object) {
super(type);
this.reason = reason;
this.params = params;
}
}

11
npm/ng-packs/packages/core/src/lib/models/auth.ts

@ -1,5 +1,6 @@
import { UnaryFunction } from 'rxjs';
import { Injector } from '@angular/core';
import { UnaryFunction } from 'rxjs';
import { AuthErrorEvent } from './auth-events';
export interface LoginParams {
username: string;
@ -13,7 +14,13 @@ export type PipeToLoginFn = (
injector: Injector,
) => UnaryFunction<any, any>;
/**
* @deprecated The interface should not be used anymore.
* @deprecated The interface should not be used anymore.
*/
export type SetTokenResponseToStorageFn<T = any> = (tokenRes: T) => void;
export type CheckAuthenticationStateFn = (injector: Injector) => void;
export interface AuthErrorFilter<T = AuthErrorEvent> {
id: string;
executable: boolean;
execute: (event: T) => boolean;
}

1
npm/ng-packs/packages/core/src/lib/models/index.ts

@ -7,3 +7,4 @@ export * from './rest';
export * from './session';
export * from './utility';
export * from './auth';
export * from './auth-events';

6
npm/ng-packs/packages/oauth/package.json

@ -9,9 +9,9 @@
"dependencies": {
"@abp/ng.core": "~7.4.4",
"@abp/utils": "~7.4.4",
"angular-oauth2-oidc": "^15.0.1",
"just-clone": "^6.1.1",
"just-compare": "^2.3.0",
"angular-oauth2-oidc": "^15.0.0",
"just-clone": "^6.0.0",
"just-compare": "^2.0.0",
"tslib": "^2.0.0"
},
"publishConfig": {

6
npm/ng-packs/packages/oauth/src/lib/oauth.module.ts

@ -1,18 +1,19 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import {
AbpLocalStorageService,
ApiInterceptor,
AuthErrorFilterService,
AuthGuard,
AuthService,
CHECK_AUTHENTICATION_STATE_FN_KEY,
noop,
PIPE_TO_LOGIN_FN_KEY,
} from '@abp/ng.core';
import { AbpOAuthService } from './services';
import { AbpOAuthService, OAuthErrorFilterService } from './services';
import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { OAuthApiInterceptor } from './interceptors/api.interceptor';
import { AbpOAuthGuard } from './guards/oauth.guard';
import { NavigateToManageProfileProvider } from './providers';
@ -60,6 +61,7 @@ export class AbpOAuthModule {
},
OAuthModule.forRoot().providers as Provider[],
{ provide: OAuthStorage, useClass: AbpLocalStorageService },
{ provide: AuthErrorFilterService, useExisting: OAuthErrorFilterService },
],
};
}

1
npm/ng-packs/packages/oauth/src/lib/services/index.ts

@ -1 +1,2 @@
export * from './oauth.service';
export * from './oauth-error-filter.service';

46
npm/ng-packs/packages/oauth/src/lib/services/oauth-error-filter.service.ts

@ -0,0 +1,46 @@
import { AbstractAuthErrorFilter, AuthErrorFilter } from '@abp/ng.core';
import { Injectable, signal } from '@angular/core';
import { OAuthErrorEvent } from 'angular-oauth2-oidc';
@Injectable({ providedIn: 'root' })
export class OAuthErrorFilterService extends AbstractAuthErrorFilter<
AuthErrorFilter<OAuthErrorEvent>,
OAuthErrorEvent
> {
readonly #filters = signal<Array<AuthErrorFilter<OAuthErrorEvent>>>([]);
filters = this.#filters.asReadonly();
get(id: string): AuthErrorFilter<OAuthErrorEvent> {
return this.#filters().find(({ id: _id }) => _id === id);
}
add(filter: AuthErrorFilter<OAuthErrorEvent>): void {
this.#filters.update(items => [...items, filter]);
}
patch(item: Partial<AuthErrorFilter<OAuthErrorEvent>>): void {
const _item = this.filters().find(({ id }) => id === item.id);
if (!_item) {
return;
}
Object.assign(_item, item);
}
remove(id: string): void {
const item = this.filters().find(({ id: _id }) => _id === id);
if (!item) {
return;
}
this.#filters.update(items => items.filter(({ id: _id }) => _id !== id));
}
run(event: OAuthErrorEvent): boolean {
return this.filters()
.filter(({ executable }) => !!executable)
.map(({ execute }) => execute(event))
.some(item => item);
}
}

6
npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts

@ -44,10 +44,10 @@ export class AbpOAuthService implements IAuthService {
}
logout(queryParams?: Params): Observable<any> {
if(!this.strategy){
return EMPTY
if (!this.strategy) {
return EMPTY;
}
return this.strategy.logout(queryParams);
}

21
npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts

@ -1,13 +1,16 @@
import { Injector } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { Params, Router } from '@angular/router';
import { Observable, of } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import {
AuthConfig,
OAuthErrorEvent,
OAuthService as OAuthService2,
OAuthStorage,
} from 'angular-oauth2-oidc';
import { Observable, of } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import {
AbpLocalStorageService,
ConfigStateService,
@ -17,9 +20,10 @@ import {
SessionStateService,
TENANT_KEY,
} from '@abp/ng.core';
import { clearOAuthStorage } from '../utils/clear-o-auth-storage';
import { oAuthStorage } from '../utils/oauth-storage';
import { HttpErrorResponse } from '@angular/common/http';
import { OAuthErrorFilterService } from '../services';
export abstract class AuthFlowStrategy {
abstract readonly isInternalAuth: boolean;
@ -34,6 +38,8 @@ export abstract class AuthFlowStrategy {
protected tenantKey: string;
protected router: Router;
protected readonly oAuthErrorFilterService: OAuthErrorFilterService;
abstract checkIfInternalAuth(queryParams?: Params): boolean;
abstract navigateToLogin(queryParams?: Params): void;
abstract logout(queryParams?: Params): Observable<any>;
@ -54,6 +60,7 @@ export abstract class AuthFlowStrategy {
this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {};
this.tenantKey = injector.get(TENANT_KEY);
this.router = injector.get(Router);
this.oAuthErrorFilterService = injector.get(OAuthErrorFilterService);
this.listenToOauthErrors();
}
@ -97,6 +104,7 @@ export abstract class AuthFlowStrategy {
if (redirect_uri && redirect_uri !== '/') {
return redirect_uri;
}
return '/';
}),
switchMap(redirectUri =>
@ -118,7 +126,12 @@ export abstract class AuthFlowStrategy {
this.oAuthService.events
.pipe(
filter(event => event instanceof OAuthErrorEvent),
tap(() => clearOAuthStorage()),
tap((err: OAuthErrorEvent) => {
const shouldSkip = this.oAuthErrorFilterService.run(err);
if (!shouldSkip) {
clearOAuthStorage();
}
}),
switchMap(() => this.configState.refreshAppState()),
)
.subscribe();

Loading…
Cancel
Save