diff --git a/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts b/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts index 720034d928..3790f8fe3f 100644 --- a/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts +++ b/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts @@ -1,5 +1,5 @@ -import { OAUTH_STRATEGY } from '@abp/ng.core'; -import { Component, Injector } from '@angular/core'; +import { AuthService } from '@abp/ng.core'; +import { Component } from '@angular/core'; import { OAuthService } from 'angular-oauth2-oidc'; @Component({ @@ -11,9 +11,9 @@ export class HomeComponent { return this.oAuthService.hasValidAccessToken(); } - constructor(private oAuthService: OAuthService, private injector: Injector) {} + constructor(private oAuthService: OAuthService, private authService: AuthService) {} login() { - OAUTH_STRATEGY.NavigateToLogin(this.injector); + this.authService.initLogin(); } } diff --git a/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts b/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts index f892916582..7cb719628e 100644 --- a/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts +++ b/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts @@ -1,12 +1,15 @@ -import { Injectable, Injector } from '@angular/core'; +import { AuthService } from '@abp/ng.core'; +import { Injectable } from '@angular/core'; import { CanActivate } from '@angular/router'; -import { OAUTH_STRATEGY } from '@abp/ng.core'; @Injectable() export class AuthenticationFlowGuard implements CanActivate { - constructor(private injector: Injector) {} + constructor(private authService: AuthService) {} canActivate() { - return OAUTH_STRATEGY.CanActivate(this.injector); + if (this.authService.isInternalAuth) return true; + + this.authService.initLogin(); + return false; } } diff --git a/npm/ng-packs/packages/core/src/lib/services/auth.service.ts b/npm/ng-packs/packages/core/src/lib/services/auth.service.ts index 3d4bdb9a0a..6502bc3a61 100644 --- a/npm/ng-packs/packages/core/src/lib/services/auth.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/auth.service.ts @@ -1,28 +1,62 @@ import { HttpHeaders } from '@angular/common/http'; import { Inject, Injectable, Injector, Optional } from '@angular/core'; import { Navigate } from '@ngxs/router-plugin'; -import { Store } from '@ngxs/store'; +import { Store, Actions, ofActionSuccessful } from '@ngxs/store'; import { OAuthService } from 'angular-oauth2-oidc'; import { from, Observable } from 'rxjs'; import { switchMap, take, tap } from 'rxjs/operators'; import snq from 'snq'; -import { GetAppConfiguration } from '../actions/config.actions'; +import { GetAppConfiguration, SetEnvironment } from '../actions/config.actions'; import { ConfigState } from '../states/config.state'; import { SessionState } from '../states/session.state'; -import { OAUTH_STRATEGY } from '../strategies/oauth.strategy'; import { RestService } from './rest.service'; +import { + AuthCodeFlowStrategy, + AuthPasswordFlowStrategy, + AUTH_FLOW_STRATEGY, +} from '../strategies/auth-flow.strategy'; @Injectable({ providedIn: 'root', }) export class AuthService { + private flow: string; + private strategy: AuthCodeFlowStrategy | AuthPasswordFlowStrategy; + + get isInternalAuth() { + return this.strategy.isInternalAuth; + } + constructor( + private actions: Actions, private injector: Injector, private rest: RestService, private oAuthService: OAuthService, private store: Store, @Optional() @Inject('ACCOUNT_OPTIONS') private options: any, - ) {} + ) { + this.setStrategy(); + this.listenToSetEnvironment(); + } + + private setStrategy = () => { + const flow = + this.store.selectSnapshot(ConfigState.getDeep('environment.oAuthConfig.responseType')) || + 'password'; + if (this.flow === flow) return; + + if (this.strategy) this.strategy.destroy(); + + this.flow = flow; + this.strategy = + this.flow === 'code' + ? AUTH_FLOW_STRATEGY.Code(this.injector) + : AUTH_FLOW_STRATEGY.Password(this.injector); + }; + + private listenToSetEnvironment() { + this.actions.pipe(ofActionSuccessful(SetEnvironment)).subscribe(this.setStrategy); + } login(username: string, password: string): Observable { const tenant = this.store.selectSnapshot(SessionState.getTenant); @@ -47,16 +81,15 @@ export class AuthService { ); } - /** - * @deprecated use LogOut prop of OAUTH_STRATEGY instead, will be deleted in v3.3 - */ + async init() { + return await this.strategy.init(); + } + logout(): Observable { - if (!this.store.selectSnapshot(ConfigState.getDeep('environment.production'))) { - console.warn( - 'The logout method of AuthService is depracated. Use LogOut prop of OAUTH_STRATEGY instead.', - ); - } + return this.strategy.logout(); + } - return OAUTH_STRATEGY.LogOut(this.injector); + initLogin() { + this.strategy.login(); } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/oauth.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts similarity index 62% rename from npm/ng-packs/packages/core/src/lib/strategies/oauth.strategy.ts rename to npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts index b01de5e936..cf8f9c039a 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/oauth.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts @@ -1,6 +1,6 @@ import { Injector } from '@angular/core'; import { Store } from '@ngxs/store'; -import { AuthConfig, OAuthService, OAuthSuccessEvent } from 'angular-oauth2-oidc'; +import { AuthConfig, OAuthService } from 'angular-oauth2-oidc'; import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens/options.token'; import { Router } from '@angular/router'; @@ -9,12 +9,18 @@ import { RestService } from '../services/rest.service'; import { switchMap } from 'rxjs/operators'; import { GetAppConfiguration } from '../actions/config.actions'; -export abstract class OAuthStrategy { +export abstract class AuthFlowStrategy { + protected abstract _isInternalAuth: boolean; + get isInternalAuth(): boolean { + return this._isInternalAuth; + } + protected oAuthService: OAuthService; protected oAuthConfig: AuthConfig; - abstract navigateToLogin(): void; - abstract canActivate(): boolean; - abstract logOut(): Observable; + abstract checkIfInternalAuth(): boolean; + abstract login(): void; + abstract logout(): Observable; + abstract destroy(): void; private catchError = err => { // TODO: handle the error @@ -31,7 +37,9 @@ export abstract class OAuthStrategy { } } -export class OAuthCodeFlowStrategy extends OAuthStrategy { +export class AuthCodeFlowStrategy extends AuthFlowStrategy { + protected _isInternalAuth = false; + async init() { return super .init() @@ -39,32 +47,36 @@ export class OAuthCodeFlowStrategy extends OAuthStrategy { .then(() => this.oAuthService.setupAutomaticSilentRefresh()); } - navigateToLogin() { + login() { this.oAuthService.initCodeFlow(); } - canActivate() { + checkIfInternalAuth() { this.oAuthService.initCodeFlow(); return false; } - logOut() { + logout() { this.oAuthService.logOut(); return of(null); } + + destroy() {} } -export class OAuthPasswordFlowStrategy extends OAuthStrategy { - navigateToLogin() { +export class AuthPasswordFlowStrategy extends AuthFlowStrategy { + protected _isInternalAuth = true; + + login() { const router = this.injector.get(Router); router.navigateByUrl('/account/login'); } - canActivate() { + checkIfInternalAuth() { return true; } - logOut() { + logout() { const store = this.injector.get(Store); const rest = this.injector.get(RestService); @@ -85,28 +97,15 @@ export class OAuthPasswordFlowStrategy extends OAuthStrategy { }), ); } + + destroy() {} } -export const OAUTH_STRATEGY = { - async Init(injector: Injector) { - return getOAuthStrategy(injector).init(); +export const AUTH_FLOW_STRATEGY = { + Code(injector: Injector) { + return new AuthCodeFlowStrategy(injector); }, - NavigateToLogin(injector: Injector) { - return getOAuthStrategy(injector).navigateToLogin(); - }, - CanActivate(injector: Injector) { - return getOAuthStrategy(injector).canActivate(); - }, - LogOut(injector: Injector) { - return getOAuthStrategy(injector).logOut(); + Password(injector: Injector) { + return new AuthPasswordFlowStrategy(injector); }, }; - -function getOAuthStrategy(injector: Injector) { - const codeFlow = - injector - .get(Store) - .selectSnapshot(ConfigState.getDeep('environment.oAuthConfig.responseType')) === 'code'; - - return codeFlow ? new OAuthCodeFlowStrategy(injector) : new OAuthPasswordFlowStrategy(injector); -} diff --git a/npm/ng-packs/packages/core/src/lib/strategies/index.ts b/npm/ng-packs/packages/core/src/lib/strategies/index.ts index d2a56ad2a6..d71f952307 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/index.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/index.ts @@ -1,3 +1,4 @@ +export * from './auth-flow.strategy'; export * from './container.strategy'; export * from './content-security.strategy'; export * from './content.strategy'; @@ -5,5 +6,4 @@ export * from './context.strategy'; export * from './cross-origin.strategy'; export * from './dom.strategy'; export * from './loading.strategy'; -export * from './oauth.strategy'; export * from './projection.strategy'; diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index 17d39ed2c0..73e986493c 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -9,7 +9,7 @@ import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens/options.token'; import { getRemoteEnv } from './environment-utils'; import { parseTenantFromUrl } from './multi-tenancy-utils'; -import { OAUTH_STRATEGY } from '../strategies/oauth.strategy'; +import { AuthService } from '../services/auth.service'; export function getInitialData(injector: Injector) { const fn = async () => { @@ -18,7 +18,7 @@ export function getInitialData(injector: Injector) { await getRemoteEnv(injector, options.environment); await parseTenantFromUrl(injector); - await OAUTH_STRATEGY.Init(injector); + await injector.get(AuthService).init(); if (options.skipGetAppConfiguration) return; diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index 850b85c248..612ce7011d 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -3120,13 +3120,6 @@ alphanum-sort@^1.0.0: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -angular-oauth2-oidc-jwks@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/angular-oauth2-oidc-jwks/-/angular-oauth2-oidc-jwks-9.0.0.tgz#f11e4e561ff423928ab63ca2cca84703a00ff85d" - integrity sha512-3hTJc7vEI/ka/nnliMcCQuDnszzL3AhGInBBbn96BO+ZOdvP/4PbEumUsDto2WRpPMPxD6HAmExwYeQWljcc5A== - dependencies: - jsrsasign "^8.0.12" - angular-oauth2-oidc@^10.0.3: version "10.0.3" resolved "https://registry.yarnpkg.com/angular-oauth2-oidc/-/angular-oauth2-oidc-10.0.3.tgz#612ef75c2e07b56592d2506f9618ee6a61857ad9" @@ -8463,11 +8456,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsrsasign@^8.0.12: - version "8.0.23" - resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-8.0.23.tgz#4427ed0bbbd809d65b8e5ac9d48ba5383b49ee0c" - integrity sha512-COwd/XmwaxBwf/6E3FO21DGK504KdjfNMYv6hVd2q6W6lzTeaL2UKQ0cIBw6SFMBCdaQl8fGUm4dHFt7Wmo9xw== - jszip@^3.1.3: version "3.5.0" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6" diff --git a/templates/app/angular/src/app/home/home.component.ts b/templates/app/angular/src/app/home/home.component.ts index 720034d928..3790f8fe3f 100644 --- a/templates/app/angular/src/app/home/home.component.ts +++ b/templates/app/angular/src/app/home/home.component.ts @@ -1,5 +1,5 @@ -import { OAUTH_STRATEGY } from '@abp/ng.core'; -import { Component, Injector } from '@angular/core'; +import { AuthService } from '@abp/ng.core'; +import { Component } from '@angular/core'; import { OAuthService } from 'angular-oauth2-oidc'; @Component({ @@ -11,9 +11,9 @@ export class HomeComponent { return this.oAuthService.hasValidAccessToken(); } - constructor(private oAuthService: OAuthService, private injector: Injector) {} + constructor(private oAuthService: OAuthService, private authService: AuthService) {} login() { - OAUTH_STRATEGY.NavigateToLogin(this.injector); + this.authService.initLogin(); } }