Friday, February 15, 2019

The basics of getting adal.js working with Angular 7.

You need a service as seen below. Note that MyModel, which could be named better, is what I offer here. When you redirect to ADFS and back you will land at the redirectUri specified below and the URL will be chased with a pound sign and then id_token= and finally a bunch of gobbledygook which is your token. You may use GetAccessToken() to fish out the token going forward and you will need to hand the token on as a bearer token to every request made to your .NET Core API so that the token may validate the user of the immediacy against Active Directory.

import { ActiveDirectorySettings } from '../models/active-directory-settings.model';
import { MyModel } from '../models/my.model';
import { Injectable } from '@angular/core';
import { ActiveDirectoryContract } from '../contracts/active-directory.contract';
import * as AuthenticationContext from 'adal-angular';
import * as adal from 'adal-angular';
import { environment } from '../../environments/environment';
@Injectable()
export class ActiveDirectoryService implements ActiveDirectoryContract {
   private settings: ActiveDirectorySettings;
   private context: adal.AuthenticationContext;
   
   constructor() {
      this.settings = {
         instance: environment.activeDirectoryServer,
         tenant: environment.activeDirectoryTenant,
         clientId: environment.activeDirectoryClient,
         redirectUri: environment.baseUrl,
         postLogoutRedirectUri: environment.baseUrl + "#/shutout"
      };
      this.context = new MyModel(this.settings);
   }
   
   public GetAccessToken() {
      return this.context.getCachedToken(this.settings.clientId);
   }
   
   public GetUserInfo() {
      return this.context.getCachedUser();
   }
   
   public HandleCallback() {
      this.context.handleWindowCallback();
   }
   
   public IsAuthenticated():boolean {
      return this.GetUserInfo() && this.GetAccessToken();
   }
   
   public Login() {
      this.context.login();
   }
   
   public Logout() {
      this.context.logOut();
   }
}

 
 

If you have { useHash: true } in your routing strategy, and you probably need this, you will find the manner in which the numbers symbol leads the token to be frustrating. It makes it so that you cannot redirect back to a route nested somewhere in your routing. Instead you have to make a custom route for id_token which Angular will interpret as, yes, a route, and then fish the token out from there in a CanActivate route guard like so:

import { Injectable, Injector } from '@angular/core';
import { ActiveDirectoryContract } from '../contracts/active-directory.contract';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { routerNgProbeToken } from '@angular/router/src/router_module';
@Injectable()
export class HomeTokenGuard implements CanActivate {
   private activeDirectoryContract:ActiveDirectoryContract;
   
   constructor(public injector: Injector, private router: Router){
      this.activeDirectoryContract = injector.get(ActiveDirectoryContract);
   }
   
   canActivate(route: ActivatedRouteSnapshot): boolean {
      let pieces = document.URL.split('=');
      if (pieces && pieces.length > 0) {
         let token = document.URL.split('=')[1];
         this.activeDirectoryContract.HandleCallback();
         let user = this.activeDirectoryContract.GetUserInfo();
      } else {
         this.router.navigate(['shutout']);
      }
      return true;
   }
}

 
 

Do not try to fight this. I tried to redirect to a static HTML page in the assets folder, use JavaScript to grab the token and then redirect to a different Angular route and then handle the token from there, but .HandleCallback() cannot deal with the double redirect. At your "home" page/route you will need a CanActivate guard to kick off the login process should one not be logged in. It should look like so:

import { Injectable, Injector } from '@angular/core';
import { ActiveDirectoryContract } from '../contracts/active-directory.contract';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { environment } from '../../environments/environment';
@Injectable()
export class HomeLoginGuard implements CanActivate {
   private activeDirectoryContract:ActiveDirectoryContract;
   
   constructor(public injector: Injector, router: Router){
      this.activeDirectoryContract = injector.get(ActiveDirectoryContract);
   }
   
   canActivate(route: ActivatedRouteSnapshot): boolean {
      if(!this.activeDirectoryContract.IsAuthenticated()) {
         this.activeDirectoryContract.Login();
      }
      return true;
   }
}

 
 

Write something to log individuals back out like so:

if (activeDirectoryContract.IsAuthenticated()){
   activeDirectoryContract.Logout();
}

No comments:

Post a Comment