Browse Source

Init new oauth-packages

pull/15201/head
Mahmut Gundogdu 4 years ago
parent
commit
4f58fdb4cc
  1. 36
      npm/ng-packs/packages/oauth/.eslintrc.json
  2. 7
      npm/ng-packs/packages/oauth/README.md
  3. 22
      npm/ng-packs/packages/oauth/jest.config.ts
  4. 12
      npm/ng-packs/packages/oauth/ng-package.json
  5. 21
      npm/ng-packs/packages/oauth/package.json
  6. 21
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  7. 39
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-code-flow-strategy.ts
  8. 103
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts
  9. 101
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts
  10. 3
      npm/ng-packs/packages/oauth/src/lib/strategies/index.ts
  11. 0
      npm/ng-packs/packages/oauth/src/public-api.ts
  12. 1
      npm/ng-packs/packages/oauth/src/test-setup.ts
  13. 17
      npm/ng-packs/packages/oauth/tsconfig.json
  14. 15
      npm/ng-packs/packages/oauth/tsconfig.lib.json
  15. 11
      npm/ng-packs/packages/oauth/tsconfig.lib.prod.json
  16. 11
      npm/ng-packs/packages/oauth/tsconfig.spec.json

36
npm/ng-packs/packages/oauth/.eslintrc.json

@ -0,0 +1,36 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"plugin:@nrwl/nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "abp",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "abp",
"style": "kebab-case"
}
]
}
},
{
"files": ["*.html"],
"extends": ["plugin:@nrwl/nx/angular-template"],
"rules": {}
}
]
}

7
npm/ng-packs/packages/oauth/README.md

@ -0,0 +1,7 @@
# oauth
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test oauth` to execute the unit tests.

22
npm/ng-packs/packages/oauth/jest.config.ts

@ -0,0 +1,22 @@
/* eslint-disable */
export default {
displayName: 'oauth',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/packages/oauth',
transform: {
'^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};

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

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

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

@ -0,0 +1,21 @@
{
"name": "@abp/ng.core",
"version": "7.0.0-rc.4",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/utils": "~7.0.0-rc.4",
"@abp/ng.core": "~7.0.0-rc.4",
"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": {
"access": "public"
}
}

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

@ -0,0 +1,21 @@
import { 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 { storageFactory } from './utils/storage.factory';
@NgModule({
imports: [CommonModule, OAuthModule2],
})
export class OAuthModule {
static forRoot(): ModuleWithProviders<OAuthModule> {
return {
ngModule: OAuthModule,
providers: [
OAuthModule2.forRoot().providers,
{ provide: OAuthStorage, useFactory: storageFactory },
{ provide: OAuthService, useClass: TimeoutLimitedOAuthService },
],
};
}
}

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

@ -0,0 +1,39 @@
import { noop } from '@abp/ng.core';
import { Params } from '@angular/router';
import { from, of } from 'rxjs';
import { AuthFlowStrategy } from './auth-flow-strategy';
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 };
}
}

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

@ -0,0 +1,103 @@
import { Injector } from '@angular/core';
import { Params } from '@angular/router';
import { AuthConfig, OAuthErrorEvent, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { Observable, of } from 'rxjs';
import { filter, switchMap, tap } from 'rxjs/operators';
import { LoginParams } from '../models/auth';
import {
ConfigStateService,
EnvironmentService,
HttpErrorReporterService,
SessionStateService,
TENANT_KEY,
} from '@abp/ng.core';
import { oAuthStorage } from './oauth-storage';
import { clearOAuthStorage } from './clear-o-auth-storage';
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();
}
}
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;
}

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

@ -0,0 +1,101 @@
import { filter, switchMap, tap } from 'rxjs/operators';
import { OAuthInfoEvent } from 'angular-oauth2-oidc';
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';
function getCookieValueByName(name: string) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : '';
}
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);
return 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();
});
}
}

3
npm/ng-packs/packages/oauth/src/lib/strategies/index.ts

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

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

1
npm/ng-packs/packages/oauth/src/test-setup.ts

@ -0,0 +1 @@
import 'jest-preset-angular/setup-jest';

17
npm/ng-packs/packages/oauth/tsconfig.json

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"target": "es2020"
}
}

15
npm/ng-packs/packages/oauth/tsconfig.lib.json

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"target": "ES2022",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"include": ["**/*.ts"]
}

11
npm/ng-packs/packages/oauth/tsconfig.lib.prod.json

@ -0,0 +1,11 @@
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false,
"target": "ES2022",
"useDefineForClassFields": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

11
npm/ng-packs/packages/oauth/tsconfig.spec.json

@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
},
"files": ["src/test-setup.ts"],
"include": ["**/*.ts"]
}
Loading…
Cancel
Save