Resubida app de ejemplo, la anterior no logueaba.
This commit is contained in:
@@ -14,4 +14,5 @@ last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
|
||||
7
.directory
Normal file
7
.directory
Normal file
@@ -0,0 +1,7 @@
|
||||
[Dolphin]
|
||||
Timestamp=2021,1,20,10,33,51
|
||||
Version=4
|
||||
ViewMode=1
|
||||
|
||||
[Settings]
|
||||
HiddenFilesShown=true
|
||||
@@ -1,6 +1,6 @@
|
||||
# OkupamicocheAngular
|
||||
# SampleOauth
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.0.7.
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.1.
|
||||
|
||||
## Development server
|
||||
|
||||
|
||||
41
angular.json
41
angular.json
@@ -3,16 +3,9 @@
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"okupamicoche-angular": {
|
||||
"sample-oauth": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
},
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
@@ -20,7 +13,7 @@
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/okupamicoche-angular",
|
||||
"outputPath": "dist/sample-oauth",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
@@ -31,7 +24,7 @@
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
@@ -46,6 +39,7 @@
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
@@ -53,13 +47,13 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -68,18 +62,18 @@
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "okupamicoche-angular:build"
|
||||
"browserTarget": "sample-oauth:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "okupamicoche-angular:build:production"
|
||||
"browserTarget": "sample-oauth:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "okupamicoche-angular:build"
|
||||
"browserTarget": "sample-oauth:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
@@ -94,7 +88,7 @@
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
@@ -116,16 +110,15 @@
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "okupamicoche-angular:serve"
|
||||
"devServerTarget": "sample-oauth:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "okupamicoche-angular:serve:production"
|
||||
"devServerTarget": "sample-oauth:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "okupamicoche-angular"
|
||||
}},
|
||||
"defaultProject": "sample-oauth"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ exports.config = {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
SELENIUM_PROMISE_MANAGER: false,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
|
||||
@@ -8,9 +8,9 @@ describe('workspace-project App', () => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', async () => {
|
||||
await page.navigateTo();
|
||||
expect(await page.getTitleText()).toEqual('okupamicoche-angular app is running!');
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('sample-oauth app is running!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
async navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl);
|
||||
navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl) as Promise<unknown>;
|
||||
}
|
||||
|
||||
async getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText();
|
||||
getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,28 +9,16 @@ module.exports = function (config) {
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/okupamicoche-angular'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/sample-oauth'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
|
||||
2126
package-lock.json
generated
2126
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "okupamicoche-angular",
|
||||
"name": "sample-oauth",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
@@ -11,31 +11,33 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^10.2.4",
|
||||
"@angular/common": "^10.2.4",
|
||||
"@angular/compiler": "^10.2.4",
|
||||
"@angular/core": "^10.2.4",
|
||||
"@angular/forms": "^10.2.4",
|
||||
"@angular/platform-browser": "^10.2.4",
|
||||
"@angular/platform-browser-dynamic": "^10.2.4",
|
||||
"@angular/router": "^10.2.4",
|
||||
"angular-oauth2-oidc": "^10.0.3",
|
||||
"@angular/animations": "~10.2.4",
|
||||
"@angular/common": "~10.2.4",
|
||||
"@angular/compiler": "~10.2.4",
|
||||
"@angular/core": "~10.2.4",
|
||||
"@angular/forms": "~10.2.4",
|
||||
"@angular/platform-browser": "~10.2.4",
|
||||
"@angular/platform-browser-dynamic": "~10.2.4",
|
||||
"@angular/router": "~10.2.4",
|
||||
"angular-oauth2-oidc": "^9.2.2",
|
||||
"angular-oauth2-oidc-jwks": "^9.0.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^1.14.1",
|
||||
"zone.js": "~0.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1100.7",
|
||||
"@angular/cli": "^10.2.1",
|
||||
"@angular/compiler-cli": "^10.2.4",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular-devkit/build-angular": "~0.1002.1",
|
||||
"@angular/cli": "~10.2.1",
|
||||
"@angular/compiler-cli": "~10.2.4",
|
||||
"@types/node": "^12.11.1",
|
||||
"@types/jasmine": "~3.5.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~5.1.0",
|
||||
"karma": "~5.0.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"protractor": "~7.0.0",
|
||||
|
||||
@@ -1,35 +1,28 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppModule]
|
||||
}).compileComponents();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
|
||||
it(`should have as title 'okupamicoche-angular'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('okupamicoche-angular');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
it('should render link to flight in a a tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain('okupamicoche-angular app is running!');
|
||||
});
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
console.log(compiled);
|
||||
expect(compiled.querySelectorAll(' li a')[2].textContent).toContain(
|
||||
'Book a Flight'
|
||||
);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
import { noDiscoveryAuthConfig } from './auth-no-discovery.config';
|
||||
import { authConfig } from './auth.config';
|
||||
import { Component } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { OAuthService, NullValidationHandler } from 'angular-oauth2-oidc';
|
||||
import { Router } from '@angular/router';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { authCodeFlowConfig } from './auth-code-flow.config';
|
||||
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||
import { useHash } from '../flags';
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
selector: 'flight-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(private router: Router, private oauthService: OAuthService) {
|
||||
this.configureCodeFlow();
|
||||
// Remember the selected configuration
|
||||
if (sessionStorage.getItem('flow') === 'code') {
|
||||
this.configureCodeFlow();
|
||||
} else {
|
||||
this.configureImplicitFlow();
|
||||
}
|
||||
|
||||
// Automatically load user profile
|
||||
this.oauthService.events
|
||||
.pipe(filter((e) => e.type === 'token_received'))
|
||||
.subscribe((_) => {
|
||||
console.log('state', this.oauthService.state);
|
||||
.pipe(filter(e => e.type === 'token_received'))
|
||||
.subscribe(_ => {
|
||||
console.debug('state', this.oauthService.state);
|
||||
this.oauthService.loadUserProfile();
|
||||
});
|
||||
}
|
||||
|
||||
private configureCodeFlow(): void {
|
||||
private configureCodeFlow() {
|
||||
this.oauthService.configure(authCodeFlowConfig);
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then((success) => {
|
||||
console.error('LOGIN success=' + success);
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(_ => {
|
||||
if (useHash) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
@@ -35,4 +42,95 @@ export class AppComponent {
|
||||
// Optional
|
||||
this.oauthService.setupAutomaticSilentRefresh();
|
||||
}
|
||||
|
||||
private configureImplicitFlow() {
|
||||
this.oauthService.configure(authConfig);
|
||||
this.oauthService.setStorage(localStorage);
|
||||
// this.oauthService.tokenValidationHandler = new JwksValidationHandler();
|
||||
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(_ => {
|
||||
if (useHash) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
|
||||
// Optional
|
||||
this.oauthService.setupAutomaticSilentRefresh();
|
||||
|
||||
// Display all events
|
||||
this.oauthService.events.subscribe(e => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.debug('oauth/oidc event', e);
|
||||
});
|
||||
|
||||
this.oauthService.events
|
||||
.pipe(filter(e => e.type === 'session_terminated'))
|
||||
.subscribe(e => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.debug('Your session has been terminated!');
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Below you find further examples for configuration functions
|
||||
//
|
||||
|
||||
private configureWithoutDiscovery() {
|
||||
this.oauthService.configure(noDiscoveryAuthConfig);
|
||||
this.oauthService.tokenValidationHandler = new NullValidationHandler();
|
||||
this.oauthService.tryLogin();
|
||||
}
|
||||
|
||||
private configureAuth() {
|
||||
//
|
||||
// This method demonstrated the old API; see configureWithNewConfigApi for new one
|
||||
//
|
||||
|
||||
// URL of the SPA to redirect the user to after login
|
||||
this.oauthService.redirectUri = window.location.origin + '/index.html';
|
||||
|
||||
// URL of the SPA to redirect the user after silent refresh
|
||||
this.oauthService.silentRefreshRedirectUri =
|
||||
window.location.origin + '/silent-refresh.html';
|
||||
|
||||
// The SPA's id. The SPA is registerd with this id at the auth-server
|
||||
this.oauthService.clientId = 'spa-demo';
|
||||
|
||||
// set the scope for the permissions the client should request
|
||||
// The first three are defined by OIDC. The 4th is a usecase-specific one
|
||||
this.oauthService.scope = 'openid profile email voucher';
|
||||
|
||||
// Url of the Identity Provider
|
||||
this.oauthService.issuer =
|
||||
'https://steyer-identity-server.azurewebsites.net/identity';
|
||||
|
||||
this.oauthService.tokenValidationHandler = new NullValidationHandler();
|
||||
|
||||
this.oauthService.events.subscribe(e => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.debug('oauth/oidc event', e);
|
||||
});
|
||||
|
||||
// Load Discovery Document and then try to login the user
|
||||
this.oauthService.loadDiscoveryDocument().then(doc => {
|
||||
this.oauthService.tryLogin();
|
||||
});
|
||||
|
||||
this.oauthService.events
|
||||
.pipe(filter(e => e.type === 'token_expires'))
|
||||
.subscribe(e => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.debug('received token_expires event', e);
|
||||
this.oauthService.silentRefresh();
|
||||
});
|
||||
}
|
||||
|
||||
private configurePasswordFlow() {
|
||||
// Set a dummy secret
|
||||
// Please note that the auth-server used here demand the client to transmit a client secret, although
|
||||
// the standard explicitly cites that the password flow can also be used without it. Using a client secret
|
||||
// does not make sense for a SPA that runs in the browser. That's why the property is called dummyClientSecret
|
||||
// Using such a dummy secreat is as safe as using no secret.
|
||||
this.oauthService.dummyClientSecret = 'geheim';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { OAuthModule } from 'angular-oauth2-oidc';
|
||||
import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
@@ -9,14 +9,17 @@ import { APP_ROUTES } from './app.routes';
|
||||
import { BASE_URL } from './app.tokens';
|
||||
import { FlightHistoryComponent } from './flight-history/flight-history.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { PasswordFlowLoginComponent } from './password-flow-login/password-flow-login.component';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
import { RouterModule, ExtraOptions } from '@angular/router';
|
||||
import { CustomPreloadingStrategy } from './shared/preload/custom-preloading.strategy';
|
||||
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
|
||||
import { useHash } from '../flags';
|
||||
|
||||
const ROUTING_OPTIONS: ExtraOptions = {
|
||||
// preloadingStrategy: CustomPreloadingStrategy,
|
||||
useHash,
|
||||
initialNavigation: 'enabled'
|
||||
useHash: useHash,
|
||||
initialNavigation: !useHash
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
@@ -29,7 +32,7 @@ const ROUTING_OPTIONS: ExtraOptions = {
|
||||
SharedModule.forRoot(),
|
||||
OAuthModule.forRoot({
|
||||
resourceServer: {
|
||||
allowedUrls: ['http://localhost:8080/api'],
|
||||
allowedUrls: ['http://www.angular.at/api'],
|
||||
sendAccessToken: true
|
||||
}
|
||||
})
|
||||
@@ -37,14 +40,15 @@ const ROUTING_OPTIONS: ExtraOptions = {
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
FlightHistoryComponent
|
||||
FlightHistoryComponent,
|
||||
PasswordFlowLoginComponent
|
||||
],
|
||||
providers: [
|
||||
// (useHash) ? { provide: LocationStrategy, useClass: HashLocationStrategy } : [],
|
||||
// {provide: AuthConfig, useValue: authConfig },
|
||||
// { provide: OAuthStorage, useValue: localStorage },
|
||||
// { provide: ValidationHandler, useClass: JwksValidationHandler },
|
||||
{ provide: BASE_URL, useValue: 'http://localhost:8080' }
|
||||
{ provide: BASE_URL, useValue: 'http://www.angular.at' }
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { PasswordFlowLoginComponent } from './password-flow-login/password-flow-login.component';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { FlightHistoryComponent } from './flight-history/flight-history.component';
|
||||
|
||||
@@ -12,6 +13,10 @@ export let APP_ROUTES: Routes = [
|
||||
path: 'home',
|
||||
component: HomeComponent
|
||||
},
|
||||
{
|
||||
path: 'password-flow-login',
|
||||
component: PasswordFlowLoginComponent
|
||||
},
|
||||
{
|
||||
path: 'flight-booking',
|
||||
loadChildren: () =>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const BASE_URL = new InjectionToken<string>('http://localhost:8080');
|
||||
export const BASE_URL = new InjectionToken<string>('BASE_URL');
|
||||
|
||||
@@ -28,8 +28,8 @@ export const authCodeFlowConfig: AuthConfig = {
|
||||
// Important: Request offline_access to get a refresh token
|
||||
// The api scope is a usecase specific one
|
||||
scope: useSilentRefreshForCodeFlow
|
||||
? 'openid profile email'
|
||||
: 'openid profile email offline_access',
|
||||
? 'openid profile email api'
|
||||
: 'openid profile email offline_access api',
|
||||
|
||||
// ^^ Please note that offline_access is not needed for silent refresh
|
||||
// At least when using idsvr, this even prevents silent refresh
|
||||
|
||||
69
src/app/auth-no-discovery.config.ts
Normal file
69
src/app/auth-no-discovery.config.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
export const noDiscoveryAuthConfig: AuthConfig = {
|
||||
clientId:
|
||||
'1004270452653-m396kcs7jc3970turlp7ffh6bv4t1b86.apps.googleusercontent.com',
|
||||
redirectUri: 'http://localhost:4200/index.html',
|
||||
postLogoutRedirectUri: '',
|
||||
loginUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
|
||||
scope: 'openid profile email',
|
||||
resource: '',
|
||||
rngUrl: '',
|
||||
oidc: true,
|
||||
requestAccessToken: true,
|
||||
options: null,
|
||||
issuer: 'https://accounts.google.com',
|
||||
clearHashAfterLogin: true,
|
||||
tokenEndpoint: 'https://www.googleapis.com/oauth2/v4/token',
|
||||
userinfoEndpoint: 'https://www.googleapis.com/oauth2/v3/userinfo',
|
||||
responseType: 'token',
|
||||
showDebugInformation: true,
|
||||
silentRefreshRedirectUri: 'http://localhost:4200/silent-refresh.html',
|
||||
silentRefreshMessagePrefix: '',
|
||||
silentRefreshShowIFrame: false,
|
||||
silentRefreshTimeout: 20000,
|
||||
dummyClientSecret: null,
|
||||
requireHttps: 'remoteOnly',
|
||||
strictDiscoveryDocumentValidation: false,
|
||||
jwks: {
|
||||
keys: [
|
||||
{
|
||||
kty: 'RSA',
|
||||
alg: 'RS256',
|
||||
use: 'sig',
|
||||
kid: '7540561fdb04b89d824a1b7b9e8849873e7cb50e',
|
||||
n:
|
||||
// tslint:disable-next-line: max-line-length
|
||||
'sSFZrLIrXzvXBCehdPR10T-mfHWFU5ZtGzW9buI7wT_tJzZ1SRUc2l1NH92kGV9bmWRtDLjWcWFwMG7rbjX25-R-62lD1k15gQiO4bhx7gbV05e36os2vXTs0ypj9GS9y8X_2fYAnxxulMLwz4m24Ejo2tQI43-V-3Tec6cSXe0FjhRaPbGdS8GHPDKkhpJ1NHMZ38vhddIImOfvtVuz3lt_zwjBsAC6Q7PHs2GOm3KtC22DCwXMYSri4QOQcasuvTlZxIQSIksTyuH0T02IH5SJvQZSx46Vfq8BM4JP-zEEjzadoyxQPouRM6TrUeaqNv5B1f1lbH6G0G_r_ddYWQ',
|
||||
e: 'AQAB'
|
||||
},
|
||||
{
|
||||
kty: 'RSA',
|
||||
alg: 'RS256',
|
||||
use: 'sig',
|
||||
kid: '778233e8f6f342ea09e867aad25f543adeebf372',
|
||||
n:
|
||||
// tslint:disable-next-line: max-line-length
|
||||
'8MMxQ9F7R1zJ57QvLX-HqUlTVLLofCzZ3-lxohJr8ivJDGZoCqll7ZTNO0nGMgnPpIO-3BQLkaNGQDCpnID1vNIjClFFl0E3cN5bDX15uxCQeQDsm25fTlphpy5FkdoHCviswtrsl2KKUPeRlKqCqMjlDO27KuxIwzIPdNSqv4tseZmI-biFt2JlO9htgODrVqaawdm27t9HcWfOK_a5czRFDHWck2-ZwjbCOF9CtF1ggYm11aV0TElExXr5fgjAQdZ1yGmJvir127BRUgyIy5cpyf7VRRf2Cv7whSMoVJr4W3OK0H9vkuFLnlBiBNYQmH_eWy5U4jBfZjBqvA7Oww',
|
||||
e: 'AQAB'
|
||||
},
|
||||
{
|
||||
kty: 'RSA',
|
||||
alg: 'RS256',
|
||||
use: 'sig',
|
||||
kid: '8ec17994394464d95b0b3d906326f1cdde8aee64',
|
||||
n:
|
||||
// tslint:disable-next-line: max-line-length
|
||||
'w49KfvzGWVXH4vyUxvP29_QTmJfvLp4RPT1WlI6Wo2aNvn6j9vRSLDrK2CnOvvrrlUKvR-8FTcyNi9pRKXDwDhEJcyVFBJVi4PqDh0KIX_dOGYCulr5FUvU0HXQxlMWSHIsJjfGbMMUwM0p09y8KHL-kipiipzn80EpBmrI4Q3t6XOAZJSmbIPaGZJDjyoWWV0TDdVDBMfkqII6tOOB7Ha189AZjz7FHYXR9CIc0Jm6rFy0tVpdHFEG3ptcNQEDQ5ghyMM4PDM4ZmQ5uk3WgHVqnpdmGEfKekLwmYFWgnI-ux_MabltIxr9TE1qubEmebM64rOusHBF0mSbEwggbyw',
|
||||
e: 'AQAB'
|
||||
}
|
||||
]
|
||||
},
|
||||
customQueryParams: null,
|
||||
silentRefreshIFrameName: 'angular-oauth-oidc-silent-refresh-iframe',
|
||||
timeoutFactor: 0.75,
|
||||
sessionCheckIntervall: 3000,
|
||||
sessionCheckIFrameName: 'angular-oauth-oidc-check-session-iframe',
|
||||
disableAtHashCheck: false,
|
||||
skipSubjectCheck: false
|
||||
};
|
||||
27
src/app/auth-password-flow.config.ts
Normal file
27
src/app/auth-password-flow.config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// This api will come in the next version
|
||||
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
export const authPasswordFlowConfig: AuthConfig = {
|
||||
// Url of the Identity Provider
|
||||
issuer: 'https://steyer-identity-server.azurewebsites.net/identity',
|
||||
|
||||
// URL of the SPA to redirect the user to after login
|
||||
redirectUri: window.location.origin + '/index.html',
|
||||
|
||||
// URL of the SPA to redirect the user after silent refresh
|
||||
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
|
||||
|
||||
// The SPA's id. The SPA is registerd with this id at the auth-server
|
||||
clientId: 'demo-resource-owner',
|
||||
|
||||
dummyClientSecret: 'geheim',
|
||||
|
||||
// set the scope for the permissions the client should request
|
||||
// The first three are defined by OIDC. The 4th is a usecase-specific one
|
||||
scope: 'openid profile email voucher',
|
||||
|
||||
showDebugInformation: true,
|
||||
|
||||
oidc: false
|
||||
};
|
||||
34
src/app/auth.config.ts
Normal file
34
src/app/auth.config.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
// This api will come in the next version
|
||||
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
export const authConfig: AuthConfig = {
|
||||
// Url of the Identity Provider
|
||||
issuer: 'https://idsvr4.azurewebsites.net',
|
||||
|
||||
// URL of the SPA to redirect the user to after login
|
||||
// redirectUri: window.location.origin
|
||||
// + ((localStorage.getItem('useHashLocationStrategy') === 'true')
|
||||
// ? '/#/index.html'
|
||||
// : '/index.html'),
|
||||
|
||||
redirectUri: window.location.origin + '/index.html',
|
||||
|
||||
// URL of the SPA to redirect the user after silent refresh
|
||||
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
|
||||
|
||||
// The SPA's id. The SPA is registerd with this id at the auth-server
|
||||
clientId: 'implicit',
|
||||
|
||||
// set the scope for the permissions the client should request
|
||||
// The first three are defined by OIDC. The 4th is a usecase-specific one
|
||||
scope: 'openid profile email api',
|
||||
|
||||
// silentRefreshShowIFrame: true,
|
||||
|
||||
showDebugInformation: true,
|
||||
|
||||
sessionChecksEnabled: true
|
||||
|
||||
// timeoutFactor: 0.01,
|
||||
};
|
||||
28
src/app/auth.google.config.ts
Normal file
28
src/app/auth.google.config.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// This api will come in the next version
|
||||
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
export const googleAuthConfig: AuthConfig = {
|
||||
// Url of the Identity Provider
|
||||
issuer: 'https://accounts.google.com',
|
||||
|
||||
// URL of the SPA to redirect the user to after login
|
||||
redirectUri: window.location.origin + '/index.html',
|
||||
|
||||
// URL of the SPA to redirect the user after silent refresh
|
||||
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
|
||||
|
||||
// The SPA's id. The SPA is registerd with this id at the auth-server
|
||||
clientId:
|
||||
'1004270452653-m396kcs7jc3970turlp7ffh6bv4t1b86.apps.googleusercontent.com',
|
||||
|
||||
strictDiscoveryDocumentValidation: false,
|
||||
|
||||
// set the scope for the permissions the client should request
|
||||
// The first three are defined by OIDC. The 4th is a usecase-specific one
|
||||
scope: 'openid profile email',
|
||||
|
||||
showDebugInformation: true,
|
||||
|
||||
sessionChecksEnabled: true
|
||||
};
|
||||
@@ -27,6 +27,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h2>Login with Implicit Flow</h2>
|
||||
<p>
|
||||
<button class="btn btn-default" (click)="loginImplicit()">Login</button>
|
||||
<button class="btn btn-default" (click)="logout()">Logout</button>
|
||||
</p>
|
||||
<b>Username/Password:</b> max/geheim
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h2>Login with Implicit Flow in popup</h2>
|
||||
<p>
|
||||
<button class="btn btn-default" (click)="loginImplicitInPopup()">
|
||||
Login
|
||||
</button>
|
||||
<button class="btn btn-default" (click)="logout()">Logout</button>
|
||||
</p>
|
||||
<p><b>Username/Password:</b> max/geheim</p>
|
||||
<p>
|
||||
<b>Note:</b> When using IE, some security settings block the communication
|
||||
with popups. This prevents that this feature works.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h2>Login with Code Flow</h2>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { authConfig } from '../auth.config';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { authCodeFlowConfig } from '../auth-code-flow.config';
|
||||
@@ -7,7 +8,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
templateUrl: './home.component.html'
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
loginFailed = false;
|
||||
loginFailed: boolean = false;
|
||||
userProfile: object;
|
||||
usePopup: boolean;
|
||||
login: false;
|
||||
@@ -17,9 +18,9 @@ export class HomeComponent implements OnInit {
|
||||
private oauthService: OAuthService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(p => {
|
||||
this.login = p.login;
|
||||
this.login = p['login'];
|
||||
});
|
||||
|
||||
// This would directly (w/o user interaction) redirect the user to the
|
||||
@@ -33,7 +34,29 @@ export class HomeComponent implements OnInit {
|
||||
*/
|
||||
}
|
||||
|
||||
async loginCode(): Promise<void> {
|
||||
async loginImplicit() {
|
||||
// Tweak config for implicit flow
|
||||
this.oauthService.configure(authConfig);
|
||||
await this.oauthService.loadDiscoveryDocument();
|
||||
sessionStorage.setItem('flow', 'implicit');
|
||||
|
||||
this.oauthService.initLoginFlow('/some-state;p1=1;p2=2?p3=3&p4=4');
|
||||
// the parameter here is optional. It's passed around and can be used after logging in
|
||||
}
|
||||
|
||||
async loginImplicitInPopup() {
|
||||
// Tweak config for implicit flow
|
||||
this.oauthService.configure(authConfig);
|
||||
await this.oauthService.loadDiscoveryDocument();
|
||||
sessionStorage.setItem('flow', 'implicit');
|
||||
|
||||
this.oauthService.initLoginFlowInPopup().then(() => {
|
||||
this.loadUserProfile();
|
||||
});
|
||||
// the parameter here is optional. It's passed around and can be used after logging in
|
||||
}
|
||||
|
||||
async loginCode() {
|
||||
// Tweak config for code flow
|
||||
this.oauthService.configure(authCodeFlowConfig);
|
||||
await this.oauthService.loadDiscoveryDocument();
|
||||
@@ -43,7 +66,7 @@ export class HomeComponent implements OnInit {
|
||||
// the parameter here is optional. It's passed around and can be used after logging in
|
||||
}
|
||||
|
||||
async loginCodeInPopup(): Promise<void> {
|
||||
async loginCodeInPopup() {
|
||||
// Tweak config for code flow
|
||||
this.oauthService.configure(authCodeFlowConfig);
|
||||
await this.oauthService.loadDiscoveryDocument();
|
||||
@@ -54,7 +77,7 @@ export class HomeComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
logout() {
|
||||
// this.oauthService.logOut();
|
||||
this.oauthService.revokeTokenAndLogout();
|
||||
}
|
||||
@@ -63,19 +86,19 @@ export class HomeComponent implements OnInit {
|
||||
this.oauthService.loadUserProfile().then(up => (this.userProfile = up));
|
||||
}
|
||||
|
||||
get givenName(): any {
|
||||
const claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) { return null; }
|
||||
get givenName() {
|
||||
var claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) return null;
|
||||
return claims['given_name'];
|
||||
}
|
||||
|
||||
get familyName(): any {
|
||||
const claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) { return null; }
|
||||
get familyName() {
|
||||
var claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) return null;
|
||||
return claims['family_name'];
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
refresh() {
|
||||
this.oauthService.oidc = true;
|
||||
|
||||
if (
|
||||
@@ -84,12 +107,12 @@ export class HomeComponent implements OnInit {
|
||||
) {
|
||||
this.oauthService
|
||||
.refreshToken()
|
||||
.then(info => console.log('refresh ok', info))
|
||||
.then(info => console.debug('refresh ok', info))
|
||||
.catch(err => console.error('refresh error', err));
|
||||
} else {
|
||||
this.oauthService
|
||||
.silentRefresh()
|
||||
.then(info => console.log('silent refresh ok', info))
|
||||
.then(info => console.debug('silent refresh ok', info))
|
||||
.catch(err => console.error('silent refresh error', err));
|
||||
}
|
||||
}
|
||||
@@ -99,7 +122,7 @@ export class HomeComponent implements OnInit {
|
||||
localStorage.setItem('requestAccessToken', '' + value);
|
||||
}
|
||||
|
||||
get requestAccessToken(): boolean {
|
||||
get requestAccessToken() {
|
||||
return this.oauthService.requestAccessToken;
|
||||
}
|
||||
|
||||
@@ -111,23 +134,23 @@ export class HomeComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
get useHashLocationStrategy(): boolean {
|
||||
get useHashLocationStrategy() {
|
||||
return localStorage.getItem('useHashLocationStrategy') === 'true';
|
||||
}
|
||||
|
||||
get id_token(): string {
|
||||
get id_token() {
|
||||
return this.oauthService.getIdToken();
|
||||
}
|
||||
|
||||
get access_token(): string {
|
||||
get access_token() {
|
||||
return this.oauthService.getAccessToken();
|
||||
}
|
||||
|
||||
get id_token_expiration(): number {
|
||||
get id_token_expiration() {
|
||||
return this.oauthService.getIdTokenExpiration();
|
||||
}
|
||||
|
||||
get access_token_expiration(): number {
|
||||
get access_token_expiration() {
|
||||
return this.oauthService.getAccessTokenExpiration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<h1 *ngIf="!givenName">Welcome!</h1>
|
||||
<h1 *ngIf="givenName">Welcome, {{ givenName }} {{ familyName }}!</h1>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p>Login with Username/Password</p>
|
||||
|
||||
<p style="color:red; font-weight:bold" *ngIf="loginFailed">
|
||||
Login wasn't successfull.
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input class="form-control" [(ngModel)]="userName" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input class="form-control" type="password" [(ngModel)]="password" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-default" (click)="loginWithPassword()">
|
||||
Login
|
||||
</button>
|
||||
<button class="btn btn-default" (click)="logout()">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body"><b>Username/Password:</b> max/geheim</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p><b>access_token_expiration:</b> {{ access_token_expiration }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p><b>access_token:</b> {{ access_token }}</p>
|
||||
<div *ngIf="userProfile">
|
||||
<b>user profile:</b>
|
||||
<pre>{{ userProfile | json }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
69
src/app/password-flow-login/password-flow-login.component.ts
Normal file
69
src/app/password-flow-login/password-flow-login.component.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { authPasswordFlowConfig } from '../auth-password-flow.config';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-flow-login',
|
||||
templateUrl: './password-flow-login.component.html'
|
||||
})
|
||||
export class PasswordFlowLoginComponent implements OnInit {
|
||||
userName: string;
|
||||
password: string;
|
||||
loginFailed: boolean = false;
|
||||
userProfile: object;
|
||||
|
||||
constructor(private oauthService: OAuthService) {
|
||||
// Tweak config for password flow
|
||||
// This is just needed b/c this demo uses both,
|
||||
// implicit flow as well as password flow
|
||||
|
||||
this.oauthService.configure(authPasswordFlowConfig);
|
||||
this.oauthService.loadDiscoveryDocument();
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
loadUserProfile(): void {
|
||||
this.oauthService.loadUserProfile().then(up => (this.userProfile = up));
|
||||
}
|
||||
|
||||
get access_token() {
|
||||
return this.oauthService.getAccessToken();
|
||||
}
|
||||
|
||||
get access_token_expiration() {
|
||||
return this.oauthService.getAccessTokenExpiration();
|
||||
}
|
||||
|
||||
get givenName() {
|
||||
var claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) return null;
|
||||
return claims['given_name'];
|
||||
}
|
||||
|
||||
get familyName() {
|
||||
var claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) return null;
|
||||
return claims['family_name'];
|
||||
}
|
||||
|
||||
loginWithPassword() {
|
||||
this.oauthService
|
||||
.fetchTokenUsingPasswordFlowAndLoadUserProfile(
|
||||
this.userName,
|
||||
this.password
|
||||
)
|
||||
.then(() => {
|
||||
console.debug('successfully logged in');
|
||||
this.loginFailed = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('error logging in', err);
|
||||
this.loginFailed = true;
|
||||
});
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.oauthService.logOut(true);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { OAuthService } from 'angular-oauth2-oidc';
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private router: Router, private oauthService: OAuthService) {}
|
||||
|
||||
canActivate(): boolean {
|
||||
canActivate() {
|
||||
if (
|
||||
this.oauthService.hasValidAccessToken() &&
|
||||
this.oauthService.hasValidIdToken()
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
|
||||
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 948 B After Width: | Height: | Size: 5.3 KiB |
@@ -1,13 +1,14 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OkupamicocheAngular</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Sample</title>
|
||||
<base href="/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<flight-app></flight-app>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
||||
@@ -11,53 +11,41 @@
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE11 requires the following for NgClass support on SVG elements */
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
/** IE10 and IE11 requires the following to support `@angular/animation`. */
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
/** Evergreen browsers require these. **/
|
||||
|
||||
/** ALL Firefox browsers require the following to support `@angular/animation`. **/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
* Zone JS is required by Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date, currency, decimal and percent pipes.
|
||||
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
*/
|
||||
// import 'intl'; // Run `npm install --save intl`.
|
||||
/**
|
||||
* Need to import at least one locale-data with intl.
|
||||
*/
|
||||
// import 'intl/locale-data/jsonp/en';
|
||||
|
||||
@@ -7,12 +7,7 @@ import {
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": false,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
@@ -20,10 +16,5 @@
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user