import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http'; import { Observable } from "rxjs/Observable"; import { Adal4Service } from '../adal/adal4.service'; import { Router } from '@angular/router'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor( private adalService: Adal4Service, private router: Router ) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const resource = this.adalService.GetResourceForEndpoint(request.url); let authenticatedCall: Observable<HttpEvent<any>>; if (resource) { if (this.adalService.userInfo.authenticated) { authenticatedCall = this.adalService.acquireToken(resource) .flatMap((token: string) => { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); return next.handle(request).catch(this.handleError); }); } else { this.adalService.refreshDataFromCache(); authenticatedCall = Observable.throw(new Error('User Not Authenticated.')); } } else { authenticatedCall = next.handle(request).catch(this.handleError); } return authenticatedCall; } private handleError(err: HttpErrorResponse): Observable<any> { if (err.status === 401 || err.status === 403) { console.log(err.message); this.router.navigate(['dataService'], {}); return Observable.of(err.message); } // handle your auth error or rethrow return Observable.throw(err); } }
Adal4Interceptor
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { Adal4Service } from './adal4.service'; @Injectable() export class Adal4Interceptor implements HttpInterceptor { constructor(public adal4Service: Adal4Service) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { request = request.clone({ setHeaders: { Authorization: `Bearer ${this.adal4Service.userInfo.token}` } }); return next.handle(request); } }
adal4service
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { Adal4User } from './adal4-user'; import * as adalLib from 'adal-angular'; import { adal } from 'adal-angular'; import User = adal.User; @Injectable() export class Adal4Service { private adalContext: adal.AuthenticationContext; private adal4User: Adal4User = { authenticated: false, username: '', error: '', token: '', profile: {} }; constructor() { } public init(configOptions: adal.Config) { if (!configOptions) { throw new Error('You must set config, when calling init.'); } const existingHash = window.location.hash; let pathDefault = window.location.href; if (existingHash) { pathDefault = pathDefault.replace(existingHash, ''); } configOptions.redirectUri = configOptions.redirectUri || pathDefault; configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault; this.adalContext = adalLib.inject(configOptions); window.AuthenticationContext = this.adalContext.constructor; this.updateDataFromCache(this.adalContext.config.loginResource); } public get config(): adal.Config { return this.adalContext.config; } public get userInfo(): Adal4User { return this.adal4User; } public login(): void { this.adalContext.login(); } public loginInProgress(): boolean { return this.adalContext.loginInProgress(); } public logOut(): void { this.adalContext.logOut(); } public handleWindowCallback(): void { const hash = window.location.hash; if (this.adalContext.isCallback(hash)) { const requestInfo = this.adalContext.getRequestInfo(hash); this.adalContext.saveTokenFromHash(requestInfo); if (requestInfo.requestType === this.adalContext.REQUEST_TYPE.LOGIN) { this.updateDataFromCache(this.adalContext.config.loginResource); } else if (requestInfo.requestType === this.adalContext.REQUEST_TYPE.RENEW_TOKEN) { this.adalContext.callback = window.parent.callBackMappedToRenewStates[requestInfo.stateResponse]; } if (requestInfo.stateMatch) { if (typeof this.adalContext.callback === 'function') { if (requestInfo.requestType === this.adalContext.REQUEST_TYPE.RENEW_TOKEN) { if (requestInfo.parameters['access_token']) { this.adalContext.callback(this.adalContext._getItem(this.adalContext.CONSTANTS.STORAGE.ERROR_DESCRIPTION) , requestInfo.parameters['access_token']); } else if (requestInfo.parameters['error']) { this.adalContext.callback(this.adalContext._getItem(this.adalContext.CONSTANTS.STORAGE.ERROR_DESCRIPTION), null); this.adalContext._renewFailed = true; } } } } } if (window.location.hash) { window.location.href = window.location.href.replace(window.location.hash, ''); } } public getCachedToken(resource: string): string { return this.adalContext.getCachedToken(resource); } public acquireToken(resource: string) { const _this = this; let errorMessage: string; return Observable.bindCallback(acquireTokenInternal, function (token: string) { if (!token && errorMessage) { throw (errorMessage); } return token; })(); function acquireTokenInternal(cb: any) { let s: string = null; _this.adalContext.acquireToken(resource, (error: string, tokenOut: string) => { if (error) { _this.adalContext.error('Error when acquiring token for resource: ' + resource, error); errorMessage = error; cb(<string>null); } else { cb(tokenOut); s = tokenOut; } }); return s; } } public getUser(): Observable<any> { return Observable.bindCallback((cb: (u: adal.User) => User) => { this.adalContext.getUser(function (error: string, user: adal.User) { if (error) { this.adalContext.error('Error when getting user', error); cb(null); } else { cb(user); } }); })(); } public clearCache(): void { this.adalContext.clearCache(); } public clearCacheForResource(resource: string): void { this.adalContext.clearCacheForResource(resource); } public info(message: string): void { this.adalContext.info(message); } public verbose(message: string): void { this.adalContext.verbose(message); } public GetResourceForEndpoint(url: string): string { return this.adalContext.getResourceForEndpoint(url); } public refreshDataFromCache() { this.updateDataFromCache(this.adalContext.config.loginResource); } private updateDataFromCache(resource: string): void { const token = this.adalContext.getCachedToken(resource); this.adal4User.authenticated = token !== null && token.length > 0; const user = this.adalContext.getCachedUser() || { userName: '', profile: undefined }; if (user) { this.adal4User.username = user.userName; this.adal4User.profile = user.profile; this.adal4User.token = token; this.adal4User.error = this.adalContext.getLoginError(); } else { this.adal4User.username = ''; this.adal4User.profile = {}; this.adal4User.token = ''; this.adal4User.error = ''; } }; }
Adal4User
export class Adal4User { authenticated: boolean; username: string; error: string; profile: any; token: string; }
adal-angular.d
declare var AuthenticationContext: adal.AuthenticationContextStatic; declare namespace adal { interface Config { tenant?: string; clientId: string; redirectUri?: string; instance?: string; endpoints?: any; popUp?: boolean; localLoginUrl?: string; displayCall?: (urlNavigate: string) => any; postLogoutRedirectUri?: string; cacheLocation?: string; anonymousEndpoints?: string[]; expireOffsetSeconds?: number; correlationId?: string; loginResource?: string; resource?: string; extraQueryParameter?: string; navigateToLoginRequestUrl?: boolean; } interface User { userName: string; profile: any; } interface RequestInfo { valid: boolean; parameters: any; stateMatch: boolean; stateResponse: string; requestType: string; } interface AuthenticationContextStatic { new (config: Config): AuthenticationContext; } interface AuthenticationContext { CONSTANTS: any; REQUEST_TYPE: { LOGIN: string, RENEW_TOKEN: string, UNKNOWN: string }; callback: any; _getItem: any; _renewFailed: any; instance: string; config: Config; login(): void; loginInProgress(): boolean; getCachedToken(resource: string): string; getCachedUser(): User; registerCallback(expectedState: string, resource: string, callback: (message: string, token: string) => any): void; acquireToken(resource: string, callback: (message: string, token: string) => any): void; promptUser(urlNavigate: string): void; clearCache(): void; clearCacheForResource(resource: string): void; logOut(): void; getUser(callback: (message: string, user?: User) => any): void; isCallback(hash: string): boolean; getLoginError(): string; getRequestInfo(hash: string): RequestInfo; saveTokenFromHash(requestInfo: RequestInfo): void; getResourceForEndpoint(endpoint: string): string; handleWindowCallback(): void; log(level: number, message: string, error: any): void; error(message: string, error: any): void; warn(message: string): void; info(message: string): void; verbose(message: string): void; } } interface Window { AuthenticationContext: any; callBackMappedToRenewStates: any; }
logged-in.guard
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Adal4Service } from './adal4.service'; @Injectable() export class LoggedInGuard implements CanActivate{ constructor(private adalService: Adal4Service, ) { } canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean { this.adalService.handleWindowCallback(); if (this.adalService.userInfo.authenticated) { return true; } else { this.adalService.login(); return false; } } }