Angular4 + Amazon Cognitoで認証画面作ってみた

いまさらながらAmazon Cognitoを使って認証画面を作ってみた備忘録。
せっかくなのでAngular4ベースで画面は作成。

# amazon-cognito-identity-jsで認証
amazon-cognito-identity-jsを利用してみます。インストールは簡単。

```
$ npm install amazon-cognito-identity-js --save
```

# ユーザプールを作成しユーザ情報を追加
ユーザプールを作成。設定はとりあえず全てデフォルトを選択しました。で、ユーザを追加。ただしAWSコンソールからユーザ追加をするとメールなどによる承認手続きが必要になってしまうので、手抜きのためにコマンドでユーザ追加と承認処理を実施。

```
$ aws cognito-idp sign-up --client-id <ClientId> --username <Username> --password <Password> --user-attributes Name=email,Value=<Mail Address>
$ aws cognito-idp admin-confirm-sign-up --user-pool-id <UserPoolId> --username <Username> 
```

無事ステータスが「CONFIRMED」のユーザが出来上がりました。（CONFIRMEDステータスでないと、APIでログインを試行してもVerifyしろ、というエラーが返ってきてしまう）

![スクリーンショット 2017-10-18 19.25.38.png](https://qiita-image-store.s3.amazonaws.com/0/102769/46555668-cbc9-222c-dbd2-117c9420a05b.png)


# 画面作成の参考ページ
このページを参考に認証画面ぽいモノを作成しました。

http://www.fumiononaka.com/Business/html5/FN1704013.html


すでにバージョンの違いからパッケージの内容が若干変わっているところはありますが、特に問題なく作成することはできました。

# それっぽい画面の作成
さくっとAngular4（なのかなこれ？）で作ります。

```app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

```app.component.ts
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { CognitoService } from './cognito.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [CognitoService]
})
export class AppComponent {
  userName = '';
  password = '';

  constructor(
    private cognitoService: CognitoService,
    private http: Http
  ) { }

  signIn() {
    this.cognitoService.signIn(this.userName, this.password);
  }
}

```

```app.comoponent.html
<!--The content below is only a placeholder and can be replaced.-->
<div>
  <h1>
    Amazon Cognito Test login
  </h1>
</div>
<div>
  <div id="loginId">
    <div>
      <label>Login ID: </label>
    </div>
    <div>
      <input type="text" [(ngModel)]="userName" />
    </div>
  </div>
  <div id="loginPass">
    <div>
      <label>Password: </label>
    </div>
    <div>
      <input type="password" [(ngModel)]="password" />
    </div>
  </div>

  <div id="signIn">
    <button (click)="signIn()">Sign In</button>
  </div>
</div>
```

Cognito用サービスは、最低限サインインだけを実装しました。

```cognito.service.ts
import { Injectable } from '@angular/core';
import * as AWS from 'aws-sdk';
import { CognitoUserPool, CognitoUserAttribute, CognitoUser, AuthenticationDetails } from 'amazon-cognito-identity-js';
import { environment } from '../environments/environment';

@Injectable()
export class CognitoService {
    userPool = null;
    constructor() {
        AWS.config.region = environment.region;
        const data = { UserPoolId: environment.userPoolId, ClientId: environment.clientId };
        this.userPool = new CognitoUserPool(data);
    }

    signIn(userName, password) {
        const userData = {
            Username: userName,
            Pool: this.userPool
        };

        const cognitoUser = new CognitoUser(userData);
        const authenticationData = {
            Username: userName,
            Password: password
        };

        const authenticationDetails = new AuthenticationDetails(authenticationData);
        cognitoUser.authenticateUser(authenticationDetails, {
            onSuccess: function (result) {
                alert('Sign in succeded');
            },
            onFailure: function (err) {
                alert(err);
            }
        });

        return;
    }
}
```

あとはこれらを使うための環境変数を記述すればOKです。

```environment.ts
export const environment = {
  production: false,
  region: 'xxxxxxxxx',
  userPoolId: 'xxxxxxxxxxxxxxxxxxxxx',
  clientId: 'xxxxxxxxxxxxxxxxxxx'

};
```

結果はこちらに。

https://github.com/kojiisd/angular-cognito

# アクセスしてみる
登録したユーザでアクセスしてみます。無事アクセスできました。

![スクリーンショット 2017-10-18 19.31.46.png](https://qiita-image-store.s3.amazonaws.com/0/102769/2503c960-eb5d-36be-9e6a-c40f80adda80.png)

アカウント情報を間違えたらもちろんアクセスできません。

![スクリーンショット 2017-10-18 19.31.53.png](https://qiita-image-store.s3.amazonaws.com/0/102769/268cd443-94ce-0ae9-b260-2e70d2698a6b.png)

# まとめ
だいぶ手抜きですが、Angular4ベースでCognitoを利用する画面を作成しました。Routerなどを実装できれば、それなりにCognitoを使ってのSPAが作成できそうなイメージも持てました。Angular4の勉強はもっとしないとなぁ。。。