app.public-key-service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import {environment} from '../../../environments/environment';
import { WebStorageStateStore } from 'oidc-client';
@Injectable()
export class PublicKeyService {
private tenantId = '';
private jwks_uri = `https://login.microsoftonline.com/${this.tenantId}/discovery/v2.0/keys`;
constructor(private http: HttpClient) { }
private getBaseUrl(): string {
let baseUrl = 'https://' + window.location.hostname;
if (window.location.port && window.location.port !== '443') {
baseUrl = baseUrl + ':' + window.location.port;
}
return baseUrl;
}
private getPublicKeys(): any {
return this.http.get<{ keys }>(this.jwks_uri);
}
public getClientSettings() {
const metadata = {
issuer: `https://login.microsoftonline.com/${this.tenantId}/v2.0`,
authorization_endpoint: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`,
token_endpoint: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`
};
const add_signing_keys = function (keys_array) {
return {
metadata: metadata,
singingKeys: keys_array,
authority: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`,
client_id: `${environment.secureAuthClientId}`,
redirect_uri: `${this.getBaseUrl()}/auth-callback`,
post_logout_redirect_uri: this.getBaseUrl(),
response_type: 'id_token',
scope: 'openid profile email',
filterProtocolClaims: true,
loadUserInfo: false,
automaticSilentRenew: false,
checkSessionInterval: 1000000,
userStore: new WebStorageStateStore({ store: sessionStorage })
};
};
return this.http.get<{ keys }>(this.jwks_uri).pipe(
map(val => add_signing_keys(val.keys))
);
}
}
认证-安全-授权-服务. ts
import {Injectable, OnDestroy} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import { catchError, tap } from 'rxjs/operators';
import {environment} from '../../../environments/environment';
import 'rxjs/Rx';
import {UserManager, UserManagerSettings, User, WebStorageStateStore} from 'oidc-client';
import {PublicKeyService} from '../../security/services/app.public-key-service';
import {UserService} from '../../shared/services/user.service';
import {KnownAuthenticationTypes} from '../types/known-authentication-types';
import {Login} from '../types/login';
import {LoginDto} from '../types/login-dto';
import {LoginMap} from '../types/login-map';
import {ChangePassword} from '../../settings/types/change-password';
import {ChangePasswordDto} from '../../settings/types/change-password-dto';
import {ChangePasswordMap} from '../../settings/types/change-password-map';
import {ResetPasswordRequestDto} from '../types/reset-password-request-dto';
import {BaseDto} from '../../shared/types/base-dto';
import * as Oidc from 'oidc-client';
import {Subject} from 'rxjs/Subject';
import {Router} from '@angular/router';
import {KnownRoutePath, KnownEvent} from '../../shared/types/known-routes';
@Injectable()
export class AuthenticationSecureAuthService implements OnDestroy {
private readonly loginReturnUrlKey: string = 'loginReturnUrlKey';
private user: User = null;
private manager: UserManager;
constructor(private http: HttpClient, private userService: UserService, private router: Router,private publicKeyService:PublicKeyService) {
Oidc.Log.logger = console;
Oidc.Log.level = Oidc.Log.INFO;
this.publicKeyService.getClientSettings().subscribe(
data =>{
console.log(data),
this.manager = new UserManager(data);
this.start();
}
);
}
ngOnDestroy() {
this.stop();
}
// Make a call to "login" to web API using id_token from SecureAuth
loginWithIdToken(idToken: string): Observable<Login> {
const url = `${environment.apiSecurityOrigin}/security/tokenlogin`;
const body = {idToken: idToken};
console.log('About to call web API to fetch user auth token and roles');
return this.http.post<BaseDto<LoginDto>>(url, body)
.map(baseDto => {
console.log('Returned from calling web API to fetch user auth token and roles');
const vm = LoginMap.toVm(this.extractLoginDto(baseDto.value));
if (vm.authenticationType === KnownAuthenticationTypes.Authenticated) {
this.userService.setCurrentUser(vm.authenticationToken, vm.user);
} else {
this.userService.clearCurrentUserAndToken();
}
return vm;
})
.catch(this.handleLoginError);
}
isLoggedIn(): boolean {
return this.user != null && !this.user.expired;
}
getClaims(): any {
return this.user.profile;
}
getIdToken(): string {
return this.user.id_token;
}
getLoginReturnUrl(): string {
let returnUrl: string = sessionStorage.getItem(this.loginReturnUrlKey);
if (!returnUrl) {
// Default to workqueues if sessionStorage not set.
returnUrl = '/workqueues';
}
return returnUrl;
}
setLoginReturnUrl(returnUrl: string): void {
sessionStorage.setItem(this.loginReturnUrlKey, returnUrl);
}
startAuthentication(): Promise<void> {
return this.manager.signinRedirect();
}
completeAuthentication(): Promise<void> {
return this.manager.signinRedirectCallback().then(user => {
this.user = user;
}, reason => console.log('Error in signinRedirectCallback(): ' + reason));
}
private extractLoginDto(body: any) {
return new LoginDto(body.authenticationToken, body.authentication, body.user);
}
private handleLoginError(response: Response | any) {
return Observable.throw(response);
}
private start(): void {
window.addEventListener('storage', this.storageEventListener.bind(this));
}
private storageEventListener(event) {
if (event.key === KnownEvent.LogoutEventName) {
// The user logged out of another tab, so log out here.
console.log('User logged out of another tab, so logging out now.');
this.router.navigate([KnownRoutePath.Logout]);
}
}
private stop(): void {
window.removeEventListener('storage', this.storageEventListener.bind(this));
}
}
auth. Guard.ts
import {Injectable} from '@angular/core';
import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanLoad, Route} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {UserService} from '../../shared/services/user.service';
import {AlertService} from '../../shared/services/alert.service';
import {AuthenticationSecureAuthService} from '../../security/services/authentication-secure-auth.service';
@Injectable()
export class AuthGuard implements CanActivate, CanLoad {
constructor(
private router: Router,
private userService: UserService,
private alertService: AlertService,
private authService: AuthenticationSecureAuthService
) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.checkLoggedIn(state.url);
}
canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> {
console.log(route.path);
return this.checkLoggedIn(route.path);
}
private checkLoggedIn(url: string): boolean {
const loggedIn = this.userService.isLoggedIn();
const sessionCurrent = this.userService.isSessionCurrent();
if (loggedIn && sessionCurrent) {
return true;
}
if (loggedIn && !sessionCurrent) {
this.userService.clearCurrentUserAndToken();
this.alertService.error('Your session has expired.', true);
}
if (url && url.charAt(0) !== '/') {
url = '/' + url;
}
this.authService.setLoginReturnUrl(url);
this.authService.startAuthentication();
return false;
}
}
将PublicKeyService添加到应用程序模块的提供者,如下所示:
@NgModule({
imports: [ BrowserModule ],
providers: [ PublicKeyService ],
declarations: [ AppComponent ],
exports: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
您在"Authation-secure-auth-service"中注入了public KeyService,因此您应该将getClientSettings()函数作为公共方法移动到您的"Authation-secure-auth-service"类主体中,而不是将您声明的"导出函数"移出设置类主体!
您可以像这样更改您的方法并在需要的地方订阅其结果:
public getClientSettings() {
return this.publicKeyService.getClientSettings();
}
但实际上你似乎不需要这个改变。根据您的评论,在您的AuthenticationSecureAuthService构造函数中尝试以下更改:
替换这部分代码:
this.manager = new UserManager(getClientSettings());
this.start();
有了这个:
this.publicKeyService.getClientSettings().subscribe(
data =>{
this.manager = new UserManager(data);
this.start();
}
);