AngularでAzure Active Directory認証を行う

AngularでAzure Active Directory(=AAD)認証を行う方法についてです。

## 前提

[adal-angular4: Angular 4/5/6/7 ADAL Wrapper](https://github.com/benbaran/adal-angular4)がインストールされていること

`angular4`という名前ですが、Angular8まで対応してます。

## environments.ts

```typescript
export const environment = {
  tenant: '{AADのテナントId}',
  clientId: '{認証用AADアプリケーションのアプリケーションId}'
};
```

## app.component.ts

```typescript
import { Component, OnInit } from '@angular/core';
import { AdalService } from 'adal-angular4';
import { environment } from 'src/environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  constructor(private adalService: AdalService) {
    adalService.init(
      {
        tenant: environment.tenant,
        clientId: environment.clientId,
        redirectUri: window.location.origin + '/',
      }
    );
  }

  ngOnInit() {
    this.adalService.handleWindowCallback();
  }

}

```

## app-router.module.ts

ルーティングモジュールで、アクセスの制御を行います。

認証をかけたいパスに`canActivate: [LoggedInGuard]`を指定します。

そうすることで、下記の例では`HomeComponent`を読み込む前に、`LoggedInGuard`を実行し、戻り値がTrueなら読み込みます。

```typescript
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from '../home/home.component';
import { CounterComponent } from '../counter/counter.component';
import { FetchDataComponent } from '../fetch-data/fetch-data.component';
import { LoginComponent } from '../page/login/login.component';
import { LoggedInGuard } from '../service/logged-in.guard';

const routes: Routes = [
  { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [LoggedInGuard]},
  { path: 'login', component: LoginComponent },
  { path: 'counter', component: CounterComponent },
  { path: 'fetch-data', component: FetchDataComponent },
];

@NgModule({
  declarations: [],
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [
    RouterModule
  ]
})
export class AppRouterModule { }

```



## loggedIn.guard.ts

Guardを作成する。

`this.adalService.userInfo.authenticated`がtrueでなければログイン画面(`/login`)に遷移します。

```typescript
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AdalService } from 'adal-angular4';

@Injectable({
  providedIn: 'root'
})
export class LoggedInGuard implements CanActivate {
  constructor(
    private adalService: AdalService,
    private router: Router
    ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      if (this.adalService.userInfo.authenticated) {
        return true;
      }
      sessionStorage.setItem('redirect_url', window.location.href);
      this.router.navigate(['/login']);
      return false;
  }

}

```



## login.component.ts

```typescript
import { Component, OnInit } from '@angular/core';
import { AdalService } from 'adal-angular4';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
  constructor(
    private adalService: AdalService,
    private router: Router,
  ) { }

  ngOnInit() {
    if (this.adalService.userInfo.authenticated) {
      this.router.navigate(['/']);
    } else {
      this.adalService.login(); // このメソッドが呼ばれると、MSの認証画面に
    }
  }

}

```

これで、`http://localhost:4200`にアクセスすれば、MSの認証画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/63166dcc-2ae0-3cbc-fab3-2a442fcd5d6a.png)

適切なアカウントでログインすると、ブラウザのセッションストレージにadal.idtokenとしてjwtが保存されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/969f1e0e-e74e-bc61-4f40-fc7331f45579.png)