Browse Source

Move auth logic to ng-oauth packages

pull/15201/head
Mahmut Gundogdu 3 years ago
parent
commit
05c5a4a0ad
  1. 285
      npm/ng-packs/angular.json
  2. 2
      npm/ng-packs/apps/dev-app/src/app/app.module.ts
  3. 4
      npm/ng-packs/apps/dev-app/src/app/home/home.component.ts
  4. 12
      npm/ng-packs/package.json
  5. 15
      npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts
  6. 59
      npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts
  7. 2
      npm/ng-packs/packages/core/src/lib/abstracts/index.ts
  8. 31
      npm/ng-packs/packages/core/src/lib/core.module.ts
  9. 1
      npm/ng-packs/packages/core/src/lib/guards/index.ts
  10. 1
      npm/ng-packs/packages/core/src/lib/handlers/index.ts
  11. 2
      npm/ng-packs/packages/core/src/lib/models/index.ts
  12. 52
      npm/ng-packs/packages/core/src/lib/services/auth.service.ts
  13. 2
      npm/ng-packs/packages/core/src/lib/services/index.ts
  14. 262
      npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts
  15. 1
      npm/ng-packs/packages/core/src/lib/utils/index.ts
  16. 45
      npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts
  17. 1
      npm/ng-packs/packages/core/src/public-api.ts
  18. 6
      npm/ng-packs/packages/oauth/ng-package.json
  19. 3
      npm/ng-packs/packages/oauth/package.json
  20. 1
      npm/ng-packs/packages/oauth/src/lib/guards/index.ts
  21. 4
      npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts
  22. 1
      npm/ng-packs/packages/oauth/src/lib/handlers/index.ts
  23. 4
      npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts
  24. 4
      npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts
  25. 0
      npm/ng-packs/packages/oauth/src/lib/interceptors/index.ts
  26. 50
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  27. 2
      npm/ng-packs/packages/oauth/src/lib/services/index.ts
  28. 57
      npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts
  29. 3
      npm/ng-packs/packages/oauth/src/lib/services/timeout-limited-oauth.service.ts
  30. 17
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts
  31. 6
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts
  32. 5
      npm/ng-packs/packages/oauth/src/lib/tests/sample.spec.ts
  33. 12
      npm/ng-packs/packages/oauth/src/lib/tokens/ auth-flow-strategy.ts
  34. 1
      npm/ng-packs/packages/oauth/src/lib/tokens/index.ts
  35. 3
      npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts
  36. 21
      npm/ng-packs/packages/oauth/src/lib/utils/clear-o-auth-storage.ts
  37. 5
      npm/ng-packs/packages/oauth/src/lib/utils/index.ts
  38. 31
      npm/ng-packs/packages/oauth/src/lib/utils/init-factory.ts
  39. 1
      npm/ng-packs/packages/oauth/src/lib/utils/oauth-storage.ts
  40. 6
      npm/ng-packs/packages/oauth/src/lib/utils/storage.factory.ts
  41. 8
      npm/ng-packs/packages/oauth/src/public-api.ts
  42. 40
      npm/ng-packs/packages/schematics/collection.json
  43. 3
      npm/ng-packs/packages/theme-shared/ng-package.json
  44. 4
      npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts
  45. 3
      npm/ng-packs/tsconfig.base.json

285
npm/ng-packs/angular.json

@ -10,9 +10,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/account"
],
"outputs": ["{workspaceRoot}/dist/packages/account"],
"options": {
"project": "packages/account/ng-package.json"
},
@ -28,9 +26,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/account"
],
"outputs": ["{workspaceRoot}/coverage/packages/account"],
"options": {
"jestConfig": "packages/account/jest.config.ts",
"passWithNoTests": true
@ -39,22 +35,13 @@
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": [
"packages/account/src/**/*.ts",
"packages/account/src/**/*.html"
]
"lintFilePatterns": ["packages/account/src/**/*.ts", "packages/account/src/**/*.html"]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared",
"account-core"
]
"implicitDependencies": ["core", "theme-shared", "account-core"]
},
"account-core": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -65,9 +52,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/account-core"
],
"outputs": ["{workspaceRoot}/dist/packages/account-core"],
"options": {
"project": "packages/account-core/ng-package.json"
},
@ -83,9 +68,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/account-core"
],
"outputs": ["{workspaceRoot}/coverage/packages/account-core"],
"options": {
"jestConfig": "packages/account-core/jest.config.ts",
"passWithNoTests": true
@ -99,16 +82,11 @@
"packages/account-core/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared"
]
"implicitDependencies": ["core", "theme-shared"]
},
"components": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -119,9 +97,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/components"
],
"outputs": ["{workspaceRoot}/dist/packages/components"],
"options": {
"project": "packages/components/ng-package.json"
},
@ -137,9 +113,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/components"
],
"outputs": ["{workspaceRoot}/coverage/packages/components"],
"options": {
"jestConfig": "packages/components/jest.config.ts",
"passWithNoTests": true
@ -153,16 +127,11 @@
"packages/components/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared"
]
"implicitDependencies": ["core", "theme-shared"]
},
"core": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -173,9 +142,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/core"
],
"outputs": ["{workspaceRoot}/dist/packages/core"],
"options": {
"project": "packages/core/ng-package.json"
},
@ -191,9 +158,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/core"
],
"outputs": ["{workspaceRoot}/coverage/packages/core"],
"options": {
"jestConfig": "packages/core/jest.config.ts",
"passWithNoTests": true
@ -202,14 +167,9 @@
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": [
"packages/core/src/**/*.ts",
"packages/core/src/**/*.html"
]
"lintFilePatterns": ["packages/core/src/**/*.ts", "packages/core/src/**/*.html"]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": []
@ -223,9 +183,7 @@
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"outputs": [
"{options.outputPath}"
],
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/dev-app",
"index": "apps/dev-app/src/index.html",
@ -233,14 +191,8 @@
"polyfills": "apps/dev-app/src/polyfills.ts",
"tsConfig": "apps/dev-app/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": [
"chart.js",
"js-sha256"
],
"assets": [
"apps/dev-app/src/favicon.ico",
"apps/dev-app/src/assets"
],
"allowedCommonJsDependencies": ["chart.js", "js-sha256"],
"assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
"styles": [
{
"input": "node_modules/bootstrap/dist/css/bootstrap.rtl.min.css",
@ -341,17 +293,12 @@
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": [
"apps/dev-app/src/**/*.ts",
"apps/dev-app/src/**/*.html"
]
"lintFilePatterns": ["apps/dev-app/src/**/*.ts", "apps/dev-app/src/**/*.html"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/apps/dev-app"
],
"outputs": ["{workspaceRoot}/coverage/apps/dev-app"],
"options": {
"jestConfig": "apps/dev-app/jest.config.ts",
"passWithNoTests": true
@ -381,19 +328,13 @@
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": [
"apps/dev-app-e2e/**/*.{js,ts}"
]
"lintFilePatterns": ["apps/dev-app-e2e/**/*.{js,ts}"]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"dev-app"
]
"implicitDependencies": ["dev-app"]
},
"feature-management": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -404,9 +345,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/feature-management"
],
"outputs": ["{workspaceRoot}/dist/packages/feature-management"],
"options": {
"project": "packages/feature-management/ng-package.json"
},
@ -422,9 +361,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/feature-management"
],
"outputs": ["{workspaceRoot}/coverage/packages/feature-management"],
"options": {
"jestConfig": "packages/feature-management/jest.config.ts",
"passWithNoTests": true
@ -438,16 +375,11 @@
"packages/feature-management/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared"
]
"implicitDependencies": ["core", "theme-shared"]
},
"identity": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -458,9 +390,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/identity"
],
"outputs": ["{workspaceRoot}/dist/packages/identity"],
"options": {
"project": "packages/identity/ng-package.json"
},
@ -476,9 +406,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/identity"
],
"outputs": ["{workspaceRoot}/coverage/packages/identity"],
"options": {
"jestConfig": "packages/identity/jest.config.ts",
"passWithNoTests": true
@ -487,22 +415,54 @@
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": [
"packages/identity/src/**/*.ts",
"packages/identity/src/**/*.html"
]
"lintFilePatterns": ["packages/identity/src/**/*.ts", "packages/identity/src/**/*.html"]
},
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": ["core", "theme-shared", "permission-management"]
},
"oauth": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "library",
"root": "packages/oauth",
"sourceRoot": "packages/oauth/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": ["{workspaceRoot}/dist/packages/oauth"],
"options": {
"project": "packages/oauth/ng-package.json"
},
"outputs": [
"{options.outputFile}"
]
"configurations": {
"production": {
"tsConfig": "packages/oauth/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/oauth/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "packages/oauth/jest.config.ts",
"passWithNoTests": true
}
},
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["packages/oauth/**/*.ts", "packages/oauth/**/*.html"]
}
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared",
"permission-management"
]
"implicitDependencies": ["core"]
},
"permission-management": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -513,9 +473,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/permission-management"
],
"outputs": ["{workspaceRoot}/dist/packages/permission-management"],
"options": {
"project": "packages/permission-management/ng-package.json"
},
@ -531,9 +489,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/permission-management"
],
"outputs": ["{workspaceRoot}/coverage/packages/permission-management"],
"options": {
"jestConfig": "packages/permission-management/jest.config.ts",
"passWithNoTests": true
@ -547,16 +503,11 @@
"packages/permission-management/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared"
]
"implicitDependencies": ["core", "theme-shared"]
},
"schematics": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -567,9 +518,7 @@
"architect": {
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/schematics"
],
"outputs": ["{workspaceRoot}/coverage/packages/schematics"],
"options": {
"jestConfig": "packages/schematics/jest.config.ts",
"passWithNoTests": true
@ -583,9 +532,7 @@
"packages/schematics/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": []
@ -599,9 +546,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/setting-management"
],
"outputs": ["{workspaceRoot}/dist/packages/setting-management"],
"options": {
"project": "packages/setting-management/ng-package.json"
},
@ -617,9 +562,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/setting-management"
],
"outputs": ["{workspaceRoot}/coverage/packages/setting-management"],
"options": {
"jestConfig": "packages/setting-management/jest.config.ts",
"passWithNoTests": true
@ -633,17 +576,11 @@
"packages/setting-management/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared",
"components"
]
"implicitDependencies": ["core", "theme-shared", "components"]
},
"tenant-management": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -654,9 +591,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/tenant-management"
],
"outputs": ["{workspaceRoot}/dist/packages/tenant-management"],
"options": {
"project": "packages/tenant-management/ng-package.json"
},
@ -672,9 +607,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/tenant-management"
],
"outputs": ["{workspaceRoot}/coverage/packages/tenant-management"],
"options": {
"jestConfig": "packages/tenant-management/jest.config.ts",
"passWithNoTests": true
@ -688,17 +621,11 @@
"packages/tenant-management/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared",
"feature-management"
]
"implicitDependencies": ["core", "theme-shared", "feature-management"]
},
"theme-basic": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -709,9 +636,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/theme-basic"
],
"outputs": ["{workspaceRoot}/dist/packages/theme-basic"],
"options": {
"project": "packages/theme-basic/ng-package.json"
},
@ -727,9 +652,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/theme-basic"
],
"outputs": ["{workspaceRoot}/coverage/packages/theme-basic"],
"options": {
"jestConfig": "packages/theme-basic/jest.config.ts",
"passWithNoTests": true
@ -743,17 +666,11 @@
"packages/theme-basic/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core",
"theme-shared",
"account-core"
]
"implicitDependencies": ["core", "theme-shared", "account-core"]
},
"theme-shared": {
"$schema": "../../node_modules/nx/schemas/project-schema.json",
@ -764,9 +681,7 @@
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": [
"{workspaceRoot}/dist/packages/theme-shared"
],
"outputs": ["{workspaceRoot}/dist/packages/theme-shared"],
"options": {
"project": "packages/theme-shared/ng-package.json"
},
@ -782,9 +697,7 @@
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/packages/theme-shared"
],
"outputs": ["{workspaceRoot}/coverage/packages/theme-shared"],
"options": {
"jestConfig": "packages/theme-shared/jest.config.ts",
"passWithNoTests": true
@ -798,15 +711,11 @@
"packages/theme-shared/src/**/*.html"
]
},
"outputs": [
"{options.outputFile}"
]
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": [
"core"
]
"implicitDependencies": ["core","oauth"]
}
}
}

2
npm/ng-packs/apps/dev-app/src/app/app.module.ts

@ -14,6 +14,7 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { APP_ROUTE_PROVIDER } from './route.provider';
import { FeatureManagementModule } from '@abp/ng.feature-management';
import { AbpOAuthModule } from '@abp/ng.oauth';
@NgModule({
imports: [
@ -26,6 +27,7 @@ import { FeatureManagementModule } from '@abp/ng.feature-management';
sendNullsAsQueryParam: false,
skipGetAppConfiguration: false,
}),
AbpOAuthModule.forRoot(),
ThemeSharedModule.forRoot(),
AccountConfigModule.forRoot(),
IdentityConfigModule.forRoot(),

4
npm/ng-packs/apps/dev-app/src/app/home/home.component.ts

@ -8,10 +8,10 @@ import { OAuthService } from 'angular-oauth2-oidc';
})
export class HomeComponent {
get hasLoggedIn(): boolean {
return this.oAuthService.hasValidAccessToken();
return this.authService.isAuthenticated;
}
constructor(private oAuthService: OAuthService, private authService: AuthService) {}
constructor(private authService: AuthService) {}
login() {
this.authService.navigateToLogin();

12
npm/ng-packs/package.json

@ -86,8 +86,8 @@
"@popperjs/core": "~2.11.2",
"@schematics/angular": "~15.0.1",
"@swimlane/ngx-datatable": "^20.0.0",
"@types/jest": "28.1.8",
"@types/node": "14.14.33",
"@types/jest": "28.1.1",
"@types/node": "16.11.7",
"@typescript-eslint/eslint-plugin": "5.44.0",
"@typescript-eslint/parser": "5.44.0",
"angular-oauth2-oidc": "^15.0.1",
@ -99,7 +99,7 @@
"eslint-config-prettier": "8.1.0",
"eslint-plugin-cypress": "^2.10.3",
"got": "^11.5.2",
"jest": "28.1.3",
"jest": "28.1.1",
"jest-canvas-mock": "^2.3.1",
"jest-environment-jsdom": "28.1.1",
"jest-preset-angular": "12.2.2",
@ -119,18 +119,18 @@
"protractor": "~7.0.0",
"rxjs": "7.5.6",
"should-quote": "^1.0.0",
"ts-jest": "28.0.8",
"ts-jest": "28.0.5",
"ts-node": "10.9.1",
"ts-toolbelt": "6.15.4",
"tsickle": "^0.39.1",
"tslib": "^2.0.0",
"tslib": "^2.3.0",
"tslint": "~6.1.0",
"typescript": "4.8.4",
"zone.js": "0.11.4"
},
"dependencies": {},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}":[
"**/*.{js,jsx,ts,tsx}": [
"npx prettier --write --config .prettierrc "
]
}

15
npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts

@ -0,0 +1,15 @@
import { CanActivate, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, IAuthGuard {
canActivate(): Observable<boolean> | boolean | UrlTree {
console.error('You should add @abp/ng-oauth packages or create your own auth packages.');
return false;
}
}
export interface IAuthGuard {
canActivate(): Observable<boolean> | boolean | UrlTree;
}

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

@ -0,0 +1,59 @@
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { Observable, of } from 'rxjs';
import { LoginParams } from '../models/auth';
/**
* Abstract service for Authentication.
*/
@Injectable({
providedIn: 'root',
})
export class AuthService implements IAuthService {
constructor() {}
private warningMessage() {
console.error('You should add @abp/ng-oauth packages or create your own auth packages.');
}
init(): Promise<any> {
this.warningMessage();
return Promise.resolve(undefined);
}
login(params: LoginParams): Observable<any> {
this.warningMessage();
return of(undefined);
}
logout(queryParams?: Params): Observable<any> {
this.warningMessage();
return of(undefined);
}
navigateToLogin(queryParams?: Params): void {}
get isInternalAuth() {
throw new Error('not implemented');
return false;
}
get isAuthenticated(): boolean {
this.warningMessage();
return false;
}
}
export interface IAuthService {
get isInternalAuth(): boolean;
get isAuthenticated(): boolean;
init(): Promise<any>;
logout(queryParams?: Params): Observable<any>;
navigateToLogin(queryParams?: Params): void;
login(params: LoginParams): Observable<any>;
}

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

@ -1 +1,3 @@
export * from './ng-model.component';
export * from './auth.guard';
export * from './auth.service';

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

@ -1,9 +1,8 @@
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { OAuthModule, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { AbstractNgModelComponent } from './abstracts/ng-model.component';
import { DynamicLayoutComponent } from './components/dynamic-layout.component';
import { ReplaceableRouteContainerComponent } from './components/replaceable-route-container.component';
@ -16,9 +15,7 @@ import { InitDirective } from './directives/init.directive';
import { PermissionDirective } from './directives/permission.directive';
import { ReplaceableTemplateDirective } from './directives/replaceable-template.directive';
import { StopPropagationDirective } from './directives/stop-propagation.directive';
import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler';
import { RoutesHandler } from './handlers/routes.handler';
import { ApiInterceptor } from './interceptors/api.interceptor';
import { LocalizationModule } from './localization.module';
import { ABP } from './models/common';
import { LocalizationPipe } from './pipes/localization.pipe';
@ -27,7 +24,6 @@ import { ToInjectorPipe } from './pipes/to-injector.pipe';
import { CookieLanguageProvider } from './providers/cookie-language.provider';
import { LocaleProvider } from './providers/locale.provider';
import { LocalizationService } from './services/localization.service';
import { oAuthStorage } from './strategies/auth-flow.strategy';
import { localizationContributor, LOCALIZATIONS } from './tokens/localization.token';
import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token';
import { TENANT_KEY } from './tokens/tenant-key.token';
@ -37,12 +33,8 @@ import { getInitialData, localeInitializer } from './utils/initial-utils';
import { ShortDateTimePipe } from './pipes/short-date-time.pipe';
import { ShortTimePipe } from './pipes/short-time.pipe';
import { ShortDatePipe } from './pipes/short-date.pipe';
import { TimeoutLimitedOAuthService } from './services/timeout-limited-oauth.service';
import { IncludeLocalizationResourcesProvider } from './providers/include-localization-resources.provider';
export function storageFactory(): OAuthStorage {
return oAuthStorage;
}
import { AuthGuard } from './abstracts/auth.guard';
/**
* BaseCoreModule is the module that holds
@ -77,7 +69,6 @@ export function storageFactory(): OAuthStorage {
ShortDatePipe,
],
imports: [
OAuthModule,
CommonModule,
HttpClientModule,
FormsModule,
@ -117,7 +108,6 @@ export class BaseCoreModule {}
imports: [
BaseCoreModule,
LocalizationModule,
OAuthModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'RequestVerificationToken',
@ -138,7 +128,6 @@ export class CoreModule {
return {
ngModule: RootCoreModule,
providers: [
OAuthModule.forRoot().providers,
LocaleProvider,
CookieLanguageProvider,
{
@ -150,17 +139,6 @@ export class CoreModule {
useFactory: coreOptionsFactory,
deps: ['CORE_OPTIONS'],
},
{
provide: HTTP_INTERCEPTORS,
useExisting: ApiInterceptor,
multi: true,
},
{
provide: APP_INITIALIZER,
multi: true,
deps: [OAuthConfigurationHandler],
useFactory: noop,
},
{
provide: APP_INITIALIZER,
multi: true,
@ -185,8 +163,7 @@ export class CoreModule {
deps: [RoutesHandler],
useFactory: noop,
},
{ provide: OAuthStorage, useFactory: storageFactory },
{ provide: OAuthService, useClass: TimeoutLimitedOAuthService },
{ provide: TENANT_KEY, useValue: options.tenantKey || '__tenant' },
{
provide: LOCALIZATIONS,
@ -194,7 +171,7 @@ export class CoreModule {
useValue: localizationContributor(options.localizations),
deps: [LocalizationService],
},
IncludeLocalizationResourcesProvider
IncludeLocalizationResourcesProvider,
],
};
}

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

@ -1,2 +1 @@
export * from './auth.guard';
export * from './permission.guard';

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

@ -1,2 +1 @@
export * from './oauth-configuration.handler';
export * from './routes.handler';

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

@ -1,4 +1,3 @@
export * from './auth';
export * from './common';
export * from './dtos';
export * from './environment';
@ -7,3 +6,4 @@ export * from './replaceable-components';
export * from './rest';
export * from './session';
export * from './utility';
export * from './auth';

52
npm/ng-packs/packages/core/src/lib/services/auth.service.ts

@ -1,52 +0,0 @@
import { Injectable, Injector } from '@angular/core';
import { Params } from '@angular/router';
import { from, Observable } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import { LoginParams } from '../models/auth';
import { AuthFlowStrategy, AUTH_FLOW_STRATEGY } from '../strategies/auth-flow.strategy';
import { EnvironmentService } from './environment.service';
@Injectable({
providedIn: 'root',
})
export class AuthService {
private strategy: AuthFlowStrategy;
get isInternalAuth() {
return this.strategy.isInternalAuth;
}
constructor(protected injector: Injector) {}
async init() {
const environmentService = this.injector.get(EnvironmentService);
return environmentService
.getEnvironment$()
.pipe(
map(env => env?.oAuthConfig),
filter(oAuthConfig => !!oAuthConfig),
tap(oAuthConfig => {
this.strategy =
oAuthConfig.responseType === 'code'
? AUTH_FLOW_STRATEGY.Code(this.injector)
: AUTH_FLOW_STRATEGY.Password(this.injector);
}),
switchMap(() => from(this.strategy.init())),
take(1),
)
.toPromise();
}
logout(queryParams?: Params): Observable<any> {
return this.strategy.logout(queryParams);
}
navigateToLogin(queryParams?: Params) {
this.strategy.navigateToLogin(queryParams);
}
login(params: LoginParams) {
return this.strategy.login(params);
}
}

2
npm/ng-packs/packages/core/src/lib/services/index.ts

@ -1,4 +1,3 @@
export * from './auth.service';
export * from './config-state.service';
export * from './content-projection.service';
export * from './dom-insertion.service';
@ -19,4 +18,3 @@ export * from './routes.service';
export * from './session-state.service';
export * from './subscription.service';
export * from './track-by.service';
export * from './timeout-limited-oauth.service';

262
npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts

@ -1,262 +0,0 @@
import { HttpHeaders } from '@angular/common/http';
import { Injector } from '@angular/core';
import { Params, Router } from '@angular/router';
import {
AuthConfig,
OAuthErrorEvent,
OAuthInfoEvent,
OAuthService,
OAuthStorage
} from 'angular-oauth2-oidc';
import { from, Observable, of, pipe } from 'rxjs';
import { filter, switchMap, tap } from 'rxjs/operators';
import { LoginParams } from '../models/auth';
import { ConfigStateService } from '../services/config-state.service';
import { EnvironmentService } from '../services/environment.service';
import { HttpErrorReporterService } from '../services/http-error-reporter.service';
import { SessionStateService } from '../services/session-state.service';
import { TENANT_KEY } from '../tokens/tenant-key.token';
import { removeRememberMe, setRememberMe } from '../utils/auth-utils';
import { noop } from '../utils/common-utils';
export const oAuthStorage = localStorage;
export abstract class AuthFlowStrategy {
abstract readonly isInternalAuth: boolean;
protected httpErrorReporter: HttpErrorReporterService;
protected environment: EnvironmentService;
protected configState: ConfigStateService;
protected oAuthService: OAuthService;
protected oAuthConfig: AuthConfig;
protected sessionState: SessionStateService;
protected tenantKey: string;
abstract checkIfInternalAuth(queryParams?: Params): boolean;
abstract navigateToLogin(queryParams?: Params): void;
abstract logout(queryParams?: Params): Observable<any>;
abstract login(params?: LoginParams | Params): Observable<any>;
private catchError = err => {
this.httpErrorReporter.reportError(err);
return of(null);
};
constructor(protected injector: Injector) {
this.httpErrorReporter = injector.get(HttpErrorReporterService);
this.environment = injector.get(EnvironmentService);
this.configState = injector.get(ConfigStateService);
this.oAuthService = injector.get(OAuthService);
this.sessionState = injector.get(SessionStateService);
this.oAuthConfig = this.environment.getEnvironment().oAuthConfig;
this.tenantKey = injector.get(TENANT_KEY);
this.listenToOauthErrors();
}
async init(): Promise<any> {
const shouldClear = shouldStorageClear(
this.environment.getEnvironment().oAuthConfig.clientId,
oAuthStorage,
);
if (shouldClear) clearOAuthStorage(oAuthStorage);
this.oAuthService.configure(this.oAuthConfig);
this.oAuthService.events
.pipe(filter(event => event.type === 'token_refresh_error'))
.subscribe(() => this.navigateToLogin());
return this.oAuthService
.loadDiscoveryDocument()
.then(() => {
if (this.oAuthService.hasValidAccessToken() || !this.oAuthService.getRefreshToken()) {
return Promise.resolve();
}
return this.refreshToken();
})
.catch(this.catchError);
}
protected refreshToken() {
return this.oAuthService.refreshToken().catch(() => clearOAuthStorage());
}
protected listenToOauthErrors() {
this.oAuthService.events
.pipe(
filter(event => event instanceof OAuthErrorEvent),
tap(() => clearOAuthStorage()),
switchMap(() => this.configState.refreshAppState()),
)
.subscribe();
}
}
export class AuthCodeFlowStrategy extends AuthFlowStrategy {
readonly isInternalAuth = false;
async init() {
return super
.init()
.then(() => this.oAuthService.tryLogin().catch(noop))
.then(() => this.oAuthService.setupAutomaticSilentRefresh({}, 'access_token'));
}
navigateToLogin(queryParams?: Params) {
this.oAuthService.initCodeFlow('', this.getCultureParams(queryParams));
}
checkIfInternalAuth(queryParams?: Params) {
this.oAuthService.initCodeFlow('', this.getCultureParams(queryParams));
return false;
}
logout(queryParams?: Params) {
return from(this.oAuthService.revokeTokenAndLogout(this.getCultureParams(queryParams)));
}
login(queryParams?: Params) {
this.oAuthService.initCodeFlow('', this.getCultureParams(queryParams));
return of(null);
}
private getCultureParams(queryParams?: Params) {
const lang = this.sessionState.getLanguage();
const culture = { culture: lang, 'ui-culture': lang };
return { ...(lang && culture), ...queryParams };
}
}
export class AuthPasswordFlowStrategy extends AuthFlowStrategy {
readonly isInternalAuth = true;
private cookieKey = 'rememberMe';
private storageKey = 'passwordFlow';
private listenToTokenExpiration() {
this.oAuthService.events
.pipe(
filter(
event =>
event instanceof OAuthInfoEvent &&
event.type === 'token_expires' &&
event.info === 'access_token',
),
)
.subscribe(() => {
if (this.oAuthService.getRefreshToken()) {
this.refreshToken();
} else {
this.oAuthService.logOut();
removeRememberMe();
this.configState.refreshAppState().subscribe();
}
});
}
async init() {
if (!getCookieValueByName(this.cookieKey) && localStorage.getItem(this.storageKey)) {
this.oAuthService.logOut();
}
return super.init().then(() => this.listenToTokenExpiration());
}
navigateToLogin(queryParams?: Params) {
const router = this.injector.get(Router);
router.navigate(['/account/login'], { queryParams });
}
checkIfInternalAuth() {
return true;
}
login(params: LoginParams): Observable<any> {
const tenant = this.sessionState.getTenant();
return from(
this.oAuthService.fetchTokenUsingPasswordFlow(
params.username,
params.password,
new HttpHeaders({ ...(tenant && tenant.id && { [this.tenantKey]: tenant.id }) }),
),
).pipe(this.pipeToLogin(params));
}
pipeToLogin(params: Pick<LoginParams, 'redirectUrl' | 'rememberMe'>) {
const router = this.injector.get(Router);
return pipe(
switchMap(() => this.configState.refreshAppState()),
tap(() => {
setRememberMe(params.rememberMe);
if (params.redirectUrl) router.navigate([params.redirectUrl]);
}),
);
}
logout(queryParams?: Params) {
const router = this.injector.get(Router);
return from(this.oAuthService.revokeTokenAndLogout(queryParams)).pipe(
switchMap(() => this.configState.refreshAppState()),
tap(() => {
router.navigateByUrl('/');
removeRememberMe();
}),
);
}
protected refreshToken() {
return this.oAuthService.refreshToken().catch(() => {
clearOAuthStorage();
removeRememberMe();
});
}
}
export const AUTH_FLOW_STRATEGY = {
Code(injector: Injector) {
return new AuthCodeFlowStrategy(injector);
},
Password(injector: Injector) {
return new AuthPasswordFlowStrategy(injector);
},
};
export function clearOAuthStorage(storage: OAuthStorage = oAuthStorage) {
const keys = [
'access_token',
'id_token',
'refresh_token',
'nonce',
'PKCE_verifier',
'expires_at',
'id_token_claims_obj',
'id_token_expires_at',
'id_token_stored_at',
'access_token_stored_at',
'granted_scopes',
'session_state',
];
keys.forEach(key => storage.removeItem(key));
}
function shouldStorageClear(clientId: string, storage: OAuthStorage): boolean {
const key = 'abpOAuthClientId';
if (!storage.getItem(key)) {
storage.setItem(key, clientId);
return false;
}
const shouldClear = storage.getItem(key) !== clientId;
if (shouldClear) storage.setItem(key, clientId);
return shouldClear;
}
function getCookieValueByName(name: string) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : '';
}

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

@ -1,5 +1,4 @@
export * from './array-utils';
export * from './auth-utils';
export * from './common-utils';
export * from './date-utils';
export * from './environment-utils';

45
npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts

@ -1,16 +1,13 @@
import { registerLocaleData } from '@angular/common';
import { Injector } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { tap, catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { lastValueFrom, throwError } from 'rxjs';
import { ABP } from '../models/common';
import { Environment } from '../models/environment';
import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models';
import { AuthService } from '../services/auth.service';
import { ConfigStateService } from '../services/config-state.service';
import { EnvironmentService } from '../services/environment.service';
import { SessionStateService } from '../services/session-state.service';
import { clearOAuthStorage } from '../strategies/auth-flow.strategy';
import { CORE_OPTIONS } from '../tokens/options.token';
import { APP_INIT_ERROR_HANDLERS } from '../tokens/app-config.token';
import { getRemoteEnv } from './environment-utils';
@ -25,41 +22,29 @@ export function getInitialData(injector: Injector) {
environmentService.setState(options.environment as Environment);
await getRemoteEnv(injector, options.environment);
await parseTenantFromUrl(injector);
await injector.get(AuthService).init();
if (options.skipGetAppConfiguration) return;
return configState
.refreshAppState()
.pipe(
tap(() => checkAccessToken(injector)),
tap(() => {
const currentTenant = configState.getOne('currentTenant') as CurrentTenantDto;
injector.get(SessionStateService).setTenant(currentTenant);
}),
catchError(error => {
const appInitErrorHandlers = injector.get(APP_INIT_ERROR_HANDLERS, null);
if (appInitErrorHandlers && appInitErrorHandlers.length) {
appInitErrorHandlers.forEach(func => func(error));
}
const result$ = configState.refreshAppState().pipe(
tap(() => {
const currentTenant = configState.getOne('currentTenant') as CurrentTenantDto;
injector.get(SessionStateService).setTenant(currentTenant);
}),
catchError(error => {
const appInitErrorHandlers = injector.get(APP_INIT_ERROR_HANDLERS, null);
if (appInitErrorHandlers && appInitErrorHandlers.length) {
appInitErrorHandlers.forEach(func => func(error));
}
return throwError(error);
}),
)
.toPromise();
return throwError(error);
}),
);
await lastValueFrom(result$);
};
return fn;
}
export function checkAccessToken(injector: Injector) {
const configState = injector.get(ConfigStateService);
const oAuth = injector.get(OAuthService);
if (oAuth.hasValidAccessToken() && !configState.getDeep('currentUser.id')) {
clearOAuthStorage();
}
}
export function localeInitializer(injector: Injector) {
const fn = () => {
const sessionState = injector.get(SessionStateService);

1
npm/ng-packs/packages/core/src/public-api.ts

@ -6,7 +6,6 @@ export * from './lib/core.module';
export * from './lib/directives';
export * from './lib/enums';
export * from './lib/guards';
export * from './lib/interceptors';
export * from './lib/localization.module';
export * from './lib/models';
export * from './lib/pipes';

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

@ -1,12 +1,14 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/packages/core",
"dest": "../../dist/packages/oauth",
"lib": {
"entryFile": "src/public-api.ts"
},
"allowedNonPeerDependencies": [
"@abp/utils",
"@abp/ng.core",
"angular-oauth2-oidc"
"angular-oauth2-oidc",
"just-clone",
"just-compare"
]
}

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

@ -1,5 +1,5 @@
{
"name": "@abp/ng.core",
"name": "@abp/ng.oauth",
"version": "7.0.0-rc.4",
"homepage": "https://abp.io",
"repository": {
@ -12,7 +12,6 @@
"angular-oauth2-oidc": "^15.0.1",
"just-clone": "^6.1.1",
"just-compare": "^1.4.0",
"ts-toolbelt": "6.15.4",
"tslib": "^2.0.0"
},
"publishConfig": {

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

@ -0,0 +1 @@
export * from './oauth.guard';

4
npm/ng-packs/packages/core/src/lib/guards/auth.guard.ts → npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts

@ -2,12 +2,12 @@ import { Injectable } from '@angular/core';
import { CanActivate, UrlTree } from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
import { AuthService, IAuthGuard } from '@abp/ng.core';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
export class AbpOAuthGuard implements CanActivate, IAuthGuard {
constructor(private oauthService: OAuthService, private authService: AuthService) {}
canActivate(): Observable<boolean> | boolean | UrlTree {

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

@ -0,0 +1 @@
export * from './oauth-configuration.handler';

4
npm/ng-packs/packages/core/src/lib/handlers/oauth-configuration.handler.ts → npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts

@ -2,9 +2,7 @@ import { Inject, Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import compare from 'just-compare';
import { filter, map } from 'rxjs/operators';
import { ABP } from '../models/common';
import { EnvironmentService } from '../services/environment.service';
import { CORE_OPTIONS } from '../tokens/options.token';
import { ABP, EnvironmentService, CORE_OPTIONS } from '@abp/ng.core';
@Injectable({
providedIn: 'root',

4
npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts → npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts

@ -2,9 +2,7 @@ import { HttpHandler, HttpHeaders, HttpInterceptor, HttpRequest } from '@angular
import { Inject, Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { finalize } from 'rxjs/operators';
import { SessionStateService } from '../services/session-state.service';
import { HttpWaitService } from '../services/http-wait.service';
import { TENANT_KEY } from '../tokens/tenant-key.token';
import { SessionStateService, HttpWaitService, TENANT_KEY } from '@abp/ng.core';
@Injectable({
providedIn: 'root',

0
npm/ng-packs/packages/core/src/lib/interceptors/index.ts → npm/ng-packs/packages/oauth/src/lib/interceptors/index.ts

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

@ -1,20 +1,52 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OAuthModule as OAuthModule2, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { TimeoutLimitedOAuthService } from '@abp/ng.core';
import { OAuthModule, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { AuthGuard, AuthService, noop } from '@abp/ng.core';
import { storageFactory } from './utils/storage.factory';
import { AbpOAuthService, TimeoutLimitedOAuthService } from './services';
import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler';
import { initFactory } from './utils/init-factory';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { ApiInterceptor } from './interceptors/api.interceptor';
import { AbpOAuthGuard } from './guards/oauth.guard';
@NgModule({
imports: [CommonModule, OAuthModule2],
imports: [CommonModule, OAuthModule],
})
export class OAuthModule {
static forRoot(): ModuleWithProviders<OAuthModule> {
export class AbpOAuthModule {
static forRoot(): ModuleWithProviders<AbpOAuthModule> {
return {
ngModule: OAuthModule,
ngModule: AbpOAuthModule,
providers: [
OAuthModule2.forRoot().providers,
{
provide: AuthService,
useClass: AbpOAuthService,
},
{
provide: AuthGuard,
useClass: AbpOAuthGuard,
},
{
provide: HTTP_INTERCEPTORS,
useExisting: ApiInterceptor,
multi: true,
},
{
provide: APP_INITIALIZER,
multi: true,
deps: [OAuthConfigurationHandler],
useFactory: noop,
},
{
provide: APP_INITIALIZER,
multi: true,
deps: [Injector],
useFactory: initFactory,
},
OAuthModule.forRoot().providers,
{ provide: OAuthStorage, useFactory: storageFactory },
{ provide: OAuthService, useClass: TimeoutLimitedOAuthService },
// {provide: OAuthService, useClass: TimeoutLimitedOAuthService}
],
};
}

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

@ -0,0 +1,2 @@
export * from './oauth.service';
export * from './timeout-limited-oauth.service';

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

@ -0,0 +1,57 @@
import { Injectable, Injector } from '@angular/core';
import { Params } from '@angular/router';
import { from, Observable, lastValueFrom } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import { IAuthService, LoginParams } from '@abp/ng.core';
import { AuthFlowStrategy } from '../strategies';
import { EnvironmentService } from '@abp/ng.core';
import { AUTH_FLOW_STRATEGY } from '../tokens/ auth-flow-strategy';
import { OAuthService } from 'angular-oauth2-oidc';
@Injectable({
providedIn: 'root',
})
export class AbpOAuthService implements IAuthService {
private strategy: AuthFlowStrategy;
get isInternalAuth() {
return this.strategy.isInternalAuth;
}
constructor(protected injector: Injector, private oAuthService: OAuthService) {}
async init() {
const environmentService = this.injector.get(EnvironmentService);
const result$ = environmentService.getEnvironment$().pipe(
map(env => env?.oAuthConfig),
filter(oAuthConfig => !!oAuthConfig),
tap(oAuthConfig => {
this.strategy =
oAuthConfig.responseType === 'code'
? AUTH_FLOW_STRATEGY.Code(this.injector)
: AUTH_FLOW_STRATEGY.Password(this.injector);
}),
switchMap(() => from(this.strategy.init())),
take(1),
);
return await lastValueFrom(result$);
}
logout(queryParams?: Params): Observable<any> {
return this.strategy.logout(queryParams);
}
navigateToLogin(queryParams?: Params) {
this.strategy.navigateToLogin(queryParams);
}
login(params: LoginParams) {
return this.strategy.login(params);
}
get isAuthenticated(): boolean {
return this.oAuthService.hasValidAccessToken();
}
}

3
npm/ng-packs/packages/core/src/lib/services/timeout-limited-oauth.service.ts → npm/ng-packs/packages/oauth/src/lib/services/timeout-limited-oauth.service.ts

@ -1,6 +1,7 @@
import { Injectable, NgZone, Optional } from '@angular/core';
import { Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
/** * @deprecated No need to override official service. It should be fixed in 15 or never version of angular-oauth2-oidc*/
@Injectable()
export class TimeoutLimitedOAuthService extends OAuthService {
protected override calcTimeout(storedAt: number, expiration: number): number {

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

@ -1,18 +1,23 @@
import { Injector } from '@angular/core';
import { Params } from '@angular/router';
import { AuthConfig, OAuthErrorEvent, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import {
AuthConfig,
OAuthErrorEvent,
OAuthService as OAuthService2,
OAuthStorage,
} from 'angular-oauth2-oidc';
import { Observable, of } from 'rxjs';
import { filter, switchMap, tap } from 'rxjs/operators';
import { LoginParams } from '../models/auth';
import {
LoginParams,
ConfigStateService,
EnvironmentService,
HttpErrorReporterService,
SessionStateService,
TENANT_KEY,
} from '@abp/ng.core';
import { oAuthStorage } from './oauth-storage';
import { clearOAuthStorage } from './clear-o-auth-storage';
import { clearOAuthStorage } from '../utils/clear-o-auth-storage';
import { oAuthStorage } from '../utils/oauth-storage';
export abstract class AuthFlowStrategy {
abstract readonly isInternalAuth: boolean;
@ -20,7 +25,7 @@ export abstract class AuthFlowStrategy {
protected httpErrorReporter: HttpErrorReporterService;
protected environment: EnvironmentService;
protected configState: ConfigStateService;
protected oAuthService: OAuthService;
protected oAuthService: OAuthService2;
protected oAuthConfig: AuthConfig;
protected sessionState: SessionStateService;
protected tenantKey: string;
@ -42,7 +47,7 @@ export abstract class AuthFlowStrategy {
this.httpErrorReporter = injector.get(HttpErrorReporterService);
this.environment = injector.get(EnvironmentService);
this.configState = injector.get(ConfigStateService);
this.oAuthService = injector.get(OAuthService);
this.oAuthService = injector.get(OAuthService2);
this.sessionState = injector.get(SessionStateService);
this.oAuthConfig = this.environment.getEnvironment().oAuthConfig;
this.tenantKey = injector.get(TENANT_KEY);

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

@ -4,9 +4,9 @@ import { Params, Router } from '@angular/router';
import { from, Observable, pipe } from 'rxjs';
import { HttpHeaders } from '@angular/common/http';
import { AuthFlowStrategy } from './auth-flow-strategy';
import { removeRememberMe, setRememberMe } from './auth-utils';
import { LoginParams } from '../models';
import { clearOAuthStorage } from './clear-o-auth-storage';
import { removeRememberMe, setRememberMe } from '../utils/auth-utils';
import { LoginParams } from '@abp/ng.core';
import { clearOAuthStorage } from '../utils/clear-o-auth-storage';
function getCookieValueByName(name: string) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));

5
npm/ng-packs/packages/oauth/src/lib/tests/sample.spec.ts

@ -0,0 +1,5 @@
describe('Test', () => {
it('should be passed', () => {
expect(true).toBe(true);
});
});

12
npm/ng-packs/packages/oauth/src/lib/tokens/ auth-flow-strategy.ts

@ -0,0 +1,12 @@
import { Injector } from '@angular/core';
import { AuthCodeFlowStrategy } from '../strategies/auth-code-flow-strategy';
import { AuthPasswordFlowStrategy } from '../strategies/auth-password-flow-strategy';
export const AUTH_FLOW_STRATEGY = {
Code(injector: Injector) {
return new AuthCodeFlowStrategy(injector);
},
Password(injector: Injector) {
return new AuthPasswordFlowStrategy(injector);
},
};

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

@ -0,0 +1 @@
export * from './ auth-flow-strategy';

3
npm/ng-packs/packages/core/src/lib/utils/auth-utils.ts → npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts

@ -3,8 +3,7 @@ import { Router } from '@angular/router';
import { OAuthStorage, TokenResponse } from 'angular-oauth2-oidc';
import { pipe } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { LoginParams } from '../models/auth';
import { ConfigStateService } from '../services/config-state.service';
import { ConfigStateService, LoginParams } from '@abp/ng.core';
const cookieKey = 'rememberMe';
const storageKey = 'passwordFlow';

21
npm/ng-packs/packages/oauth/src/lib/utils/clear-o-auth-storage.ts

@ -0,0 +1,21 @@
import { OAuthStorage } from 'angular-oauth2-oidc';
import { oAuthStorage } from './oauth-storage';
export function clearOAuthStorage(storage: OAuthStorage = oAuthStorage) {
const keys = [
'access_token',
'id_token',
'refresh_token',
'nonce',
'PKCE_verifier',
'expires_at',
'id_token_claims_obj',
'id_token_expires_at',
'id_token_stored_at',
'access_token_stored_at',
'granted_scopes',
'session_state',
];
keys.forEach(key => storage.removeItem(key));
}

5
npm/ng-packs/packages/oauth/src/lib/utils/index.ts

@ -0,0 +1,5 @@
export * from './oauth-storage';
export * from './storage.factory';
export * from './auth-utils';
export * from './clear-o-auth-storage';
export * from './init-factory';

31
npm/ng-packs/packages/oauth/src/lib/utils/init-factory.ts

@ -0,0 +1,31 @@
import { ABP, AuthService, ConfigStateService, CORE_OPTIONS } from '@abp/ng.core';
import { Injector } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { clearOAuthStorage } from './clear-o-auth-storage';
import { lastValueFrom } from 'rxjs';
import { tap } from 'rxjs/operators';
export function initFactory(injector: Injector): () => Promise<void> {
return async () => {
const authService = injector.get(AuthService);
await authService.init();
const configState = injector.get(ConfigStateService);
const options = injector.get(CORE_OPTIONS) as ABP.Root;
if (options.skipGetAppConfiguration) {
return;
}
const result$ = configState.refreshAppState().pipe(tap(() => checkAccessToken(injector)));
await lastValueFrom(result$);
};
}
export function checkAccessToken(injector: Injector) {
const configState = injector.get(ConfigStateService);
const oAuth = injector.get(OAuthService);
if (oAuth.hasValidAccessToken() && !configState.getDeep('currentUser.id')) {
clearOAuthStorage();
}
}

1
npm/ng-packs/packages/oauth/src/lib/utils/oauth-storage.ts

@ -0,0 +1 @@
export const oAuthStorage = localStorage;

6
npm/ng-packs/packages/oauth/src/lib/utils/storage.factory.ts

@ -0,0 +1,6 @@
import { OAuthStorage } from 'angular-oauth2-oidc';
import { oAuthStorage } from './oauth-storage';
export function storageFactory(): OAuthStorage {
return oAuthStorage;
}

8
npm/ng-packs/packages/oauth/src/public-api.ts

@ -0,0 +1,8 @@
export * from './lib/oauth.module';
export * from './lib/utils';
export * from './lib/tokens';
export * from './lib/services';
export * from './lib/strategies';
export * from './lib/handlers';
export * from './lib/interceptors';
export * from './lib/guards';

40
npm/ng-packs/packages/schematics/collection.json

@ -0,0 +1,40 @@
{
"schematics": {
"proxy-add": {
"description": "ABP Proxy Generator Add Schematics",
"factory": "./commands/proxy-add",
"schema": "./commands/proxy-add/schema.json"
},
"proxy-index": {
"description": "ABP Proxy Generator Index Schematics",
"factory": "./commands/proxy-index",
"schema": "./commands/proxy-index/schema.json"
},
"proxy-refresh": {
"description": "ABP Proxy Generator Refresh Schematics",
"factory": "./commands/proxy-refresh",
"schema": "./commands/proxy-refresh/schema.json"
},
"proxy-remove": {
"description": "ABP Proxy Generator Remove Schematics",
"factory": "./commands/proxy-remove",
"schema": "./commands/proxy-remove/schema.json"
},
"api": {
"description": "ABP API Generator Schematics",
"factory": "./commands/api",
"schema": "./commands/api/schema.json"
},
"create-lib": {
"description": "ABP Create Library Schematics",
"factory": "./commands/create-lib",
"schema": "./commands/create-lib/schema.json"
},
"change-theme": {
"description": "ABP Change Styles of Theme Schematics",
"factory": "./commands/change-theme",
"schema": "./commands/change-theme/schema.json"
}
}
}

3
npm/ng-packs/packages/theme-shared/ng-package.json

@ -11,6 +11,7 @@
"@ngx-validate/core",
"@swimlane/ngx-datatable",
"bootstrap",
"@popperjs/core"
"@popperjs/core",
"@abp/ng.oauth"
]
}

4
npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts

@ -83,6 +83,7 @@ export class ErrorHandler {
protected cfRes: ComponentFactoryResolver;
protected rendererFactory: RendererFactory2;
protected httpErrorConfig: HttpErrorConfig;
private authService: AuthService;
constructor(protected injector: Injector) {
this.httpErrorReporter = injector.get(HttpErrorReporterService);
@ -91,6 +92,7 @@ export class ErrorHandler {
this.cfRes = injector.get(ComponentFactoryResolver);
this.rendererFactory = injector.get(RendererFactory2);
this.httpErrorConfig = injector.get('HTTP_ERROR_CONFIG');
this.authService = this.injector.get(AuthService);
this.listenToRestError();
this.listenToRouterError();
@ -284,7 +286,7 @@ export class ErrorHandler {
}
private navigateToLogin() {
this.injector.get(AuthService).navigateToLogin();
this.authService.navigateToLogin();
}
createErrorComponent(instance: Partial<HttpErrorWrapperComponent>) {

3
npm/ng-packs/tsconfig.base.json

@ -43,7 +43,8 @@
"@abp/ng.theme.basic/testing": ["packages/theme-basic/testing/src/public-api.ts"],
"@abp/ng.theme.shared": ["packages/theme-shared/src/public-api.ts"],
"@abp/ng.theme.shared/extensions": ["packages/theme-shared/extensions/src/public-api.ts"],
"@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"]
"@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"],
"@abp/ng.oauth": ["packages/oauth/src/public-api.ts"]
}
},
"exclude": ["node_modules", "tmp"]

Loading…
Cancel
Save