【angular5项目积累总结】结合adal4实现http拦截器,token

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;
        }
    }
}