Resubida app de ejemplo, la anterior no logueaba.
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user