devise token auth api をAngular4 でUIを実装する4

「devise token auth api をAngular4 でUIを実装する4」のアイキャッチ画像

※angularの完成物のBitbucketのリンクです
Angular4-devise-token-auth

関連記事
devise token auth を使って簡単に早くAPIを作る1( api作成 )
devise token auth を使って簡単に早くAPIを作る2 ( jsonの出力 )
devise token auth api をAngular4 でUIを実装する1 ( angularのセットアップ )
devise token auth api をAngular4 でUIを実装する2
devise token auth api をAngular4 でUIを実装する3
devise token auth api をAngular4 でUIを実装する4 今回はここ

今回はログインした後にデータにアクセスできるようにしていきます

auth.service.tsを修正

ログイン機能を便利にするために修正を加える
ここでは、ログインに必要な

  • token
  • uid
  • client

情報をローカルストレージに保存できるようにします

import {Inject, Injectable, PLATFORM_ID} from '@angular/core';

// 必要なモジュールをインポート
import {Http, Headers, RequestOptions} from '@angular/http';
import 'rxjs/Rx'
import {isPlatformBrowser} from "@angular/common";


@Injectable()
export class AuthService {

  // apiのurl
  url = 'http://localhost:3000';

  constructor(@Inject(PLATFORM_ID) private platformId: Object, private http: Http) {
  }

  // token情報をローカルストレージに保存
  // 保存しておくことで、リクエストするたびに入力する手間を省く
  setToken(token: string) {
    if (isPlatformBrowser(this.platformId) && token) {
      localStorage.setItem('access-token', token);
    }
  }

  // uid = email 情報をローカルストレージに保存
  // 保存しておくことで、リクエストするたびに入力する手間を省く
  setUid(uid: string) {
    if (isPlatformBrowser(this.platformId) && uid) {
      localStorage.setItem('uid', uid);
    }
  }

  // client = 使用 端末情報をローカルストレージに保存
  // 保存しておくことで、リクエストするたびに入力する手間を省く
  setClient(client: string) {
    if (isPlatformBrowser(this.platformId) && client) {
      localStorage.setItem('client', client);
    }
  }

  // ローカルストレージに保存してあるtoken情報を取得する
  // 毎回入力することなく、tokenが有効な期間はこれで簡単にログインできる
  getToken() {
    if (isPlatformBrowser(this.platformId)) {
      return localStorage.getItem('access-token');
    } else {
      return null;
    }
  }

  // ローカルストレージに保存してあるuid情報を取得する
  getUid() {
    if (isPlatformBrowser(this.platformId) && localStorage.getItem('uid')) {
      return localStorage.getItem('uid');
    } else {
      return null;
    }
  }

  // ローカルストレージに保存してあるclient情報を取得する
  getClient() {
    if (isPlatformBrowser(this.platformId)) {
      return localStorage.getItem('client');
    } else {
      return null;
    }
  }

  // 新規登録のためのメソッド
  signUp(body: any): Promise<any> {
    let headers = new Headers({'Content-Type': 'application/json'});
    let options = new RequestOptions(({headers: headers}));
    return this.http.post(this.url + '/api/auth', body, options).toPromise();
  }

  // 引数にはログイン時に必要となる、emailとpasswordを入れる予定
  // headerはjsonだと明記する
  logIn(body: any): Promise<any> {
    let headers = new Headers({'Content-Type': 'application/json'});
    let options = new RequestOptions({headers: headers});
    return this.http.post(this.url + '/api/auth/sign_in', body, options).toPromise();

  }
}

新規登録のためのメソッドをhobby.service.tsに追加する

まずは、hobby serviceを生成します

$ ng g service hobby
Your global Angular CLI version (1.2.7) is greater than your local
version (1.0.3). The local Angular CLI version is used.

To disable this warning use "ng set --global warnings.versionMismatch=false".
installing service
  create src/app/hobby.service.spec.ts
  create src/app/hobby.service.ts
  WARNING Service is generated but not provided, it must be provided to be used

作成後はpostmanでのリクエストと同様に

  • token
  • uid
  • client

情報をheaderに付与してリクエストを行えるようにします

このheaderがTrueの場合のみ、jsonデータにアクセスできます

import {Injectable} from '@angular/core';
import {AuthService} from "./auth.service";

// 必要なモジュールをインポート
import {Http, Headers, RequestOptions} from '@angular/http';
import 'rxjs/Rx';
@Injectable()
export class HobbyService {

  url = 'http://localhost:3000';

  constructor(private http: Http, private authService: AuthService) {
  }


  findAll(): Promise<Hobby[]> {
    // header情報に token, uid, uidを付与する
    const headers = new Headers({
      'Content-Type': 'application/json',
      'access-token': this.authService.getToken(),
      'client': this.authService.getClient(),
      'uid': this.authService.getUid()
    });
    const options = new RequestOptions({headers: headers});
    return this.http.get(this.url + 'hobbies', options)
      .map(response => response.json())
      .map(data => {
        const entries: Hobby[] = [];
        data.forEach((data: any) => {
          entries.push(new Hobby(
            data['id'],
            data['name'],
            data['created_at'],
          ));
        });
        return entries;
      })
      .toPromise();
  }

}

// hobbyのオブジェクトを定義
export class Hobby {
  constructor(public id?: number,
              public name?: string,
              public created_at?: string) {
  }
}

hobby.service.tsをapp.module.tsに追加する

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';
// 追加
import {AuthService} from "./auth.service";
import {HobbyService}  from "./hobby.service";

import {LoginComponent} from './login/login.component';
import {SignUpComponent} from './sign-up/sign-up.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    SignUpComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [
    AuthService, HobbyService
  ], //追加!
  bootstrap: [AppComponent]
})
export class AppModule {
}

ログインしていればhobbyの情報をgetできるようにする

まずは、ログインした情報ローカルストレージに保存できるよう修正します

import {Component, OnInit} from '@angular/core';

//AuthServiceとLoginクラスをインポート
import {AuthService, Login} from '../auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  // オブジェクトの初期化
  sign_in = new Login();

  constructor(private authService: AuthService) {
  }

  ngOnInit() {
  }

  data(): any {
    // ログイン時に必要なデータを作成
    let body = JSON.stringify({
      'email': this.sign_in.email,
      'password': this.sign_in.password
    });
    // auth serviceのloginメソッドを body を引数として呼び出す
    // その後responseをconsoleで表示
    this.authService.logIn(body).then((response: any) => {
      
      // header情報のtoken, uid, client情報をローカルストレージにセットする
      this.authService.setToken(response.headers.get('access-token'));
      this.authService.setClient(response.headers.get('client'));
      this.authService.setUid(response.headers.get('uid'));
      console.log(response);
    });
  }

}

app.component.tsを修正

ログイン情報は完成したので、次はapp.component.tsを修正して、hobbyのデータを取得します
データは初期化時に取得 + ロードボタンも設置し、追加した後にクリックすればリロードされるようにします

import {Component, OnInit} from '@angular/core';

import {HobbyService, Hobby} from "./hobby.service";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {


  hobbies: Hobby[] = [];

  constructor(private hobbyService: HobbyService) {
  }

  // 初期化した時点でのデータを取得、表示させる
  ngOnInit() {
    this.hobbyService.findAll().then((hobbies) => {
      this.hobbies = hobbies;
      console.log(hobbies);
    }).catch((e) => console.log(e));
  }

  // データを追加した後にクリックすると、リロードできるボタン用のfunction
  getData() {
    this.ngOnInit();
  }
}
<div class="container-fluid">
  <div class="container">
    <app-login></app-login>
  </div>
  <div class="container">
    <app-sign-up></app-sign-up>
  </div>
  <div class="container">
    <button class="btn btn-primary" (click)="getData()">Hobby情報の取得</button>
    <div *ngFor="let h of hobbies">{{h.name}}</div>
  </div>
</div>

これで一通りの実装は完了です

最後のチェック

このチュートリアル通りに進めていけばこのような画面になり
401 のエラーステータスが帰ってきていると思います

次にログインしてみましょう

ログインができていたら、response情報が帰ってきます
無事にログインができたらHobby情報の取得ボタンを押してみましょう

こんな感じのデータが帰ってきます

ちなみに、このようにデータベースに情報を入れた後に

Hobby情報の取得をクリックすると

ちゃんと情報を取得できています

最後に

進むに連れて駆け足気味になってしまい、すみませんでした。。
本当はedit , deleteなどの機能もやりたかったのですが、時間の都合上できそうもないのでここまでにできればと思います

このチュートリアルはtoken ベースのログイン制限 + JSON APIの作成がメインで基本的にはこの2つをある程度使いこなせれば
クライアントサイドとバックエンド、モバイルアプリなどをトータルで作れるようになります

かなり駆け足だったので、間違いや不明点などもあるかと思いますので、気になったことがあればコメントを残してもらえると修正できるのでありがたいです

コメント(7件)

  • you&me より:

    いつも楽しくブログを拝見させております。
    rails(api)とAngularでアプリケーションの開発を行おうとしている初心者です。

    質問ですが、rails(api)とAngularについて参考になる本、webサイト等がありましたら教えて頂けないでしょうか?

    • hiyashikyuri より:

      Angularはこちらが参考になるかと思います
      私も参考本を探して見ましたが、国内外含めてあまりなかったので、HPやブログ、有料サイトで勉強した感じですね
      以下のリンクは全てWebサイト情報です

      rails api の方は割と情報はあるかと思いますが、どのような開発を行うかで勉強する範囲を絞るのも手だと思います
      ただし、情報はAngularと同じで「ドンピシャ」の部分は残念ながら少ないです。
      なので、devise_token_authとangularを組み合わせてわかりやすく便利にしようとした、という理由でこの記事をまとめたんですよ笑

      ご質問に対する回答が微妙かもしれませんが、angularやrails apiの不明点があれば、この記事にでもコメントいただければ、可能な限りお手伝いしますね!
      頑張ってください!

  • you&me より:

    ご返信ありがとうございます。
    ちなみにログイン後の画面遷移を実現したいのですがどうしたら良いでしょうか。

    ご教授していただけると幸いです

    イメージ的にはこんな感じです。
    http://jasonwatmore.com/post/2016/08/16/angular-2-jwt-authentication-example-tutorial

    • hiyashikyuri より:

      一番簡単なやり方は app.routing.ts に

      • ログイン前のルート
      • ログイン後のリダイレクトルート

      の2つを加えて、ログインがOKの状態なら、つまりstatus code === 200 ならリダイレクト画面に移動させる

      という方法が手っ取り早いのではないかと思います

  • you&me より:

    post後に返ってきたResponse {_body: “{“data”:{“id”:100}”}の中のid部分を取得する際はどうしたら良いでしょうか?

  • you&me より:

    Current_userの情報をログイン後に表示したいのですが、なかなかうまくいきません。
    何か、ヒントを頂けないでしょうか。

    • hiyashikyuri より:

      最近仕事が忙しくてなかなか時間が取れませんでした。
      申し訳ないです;;

      ここでいうCurrent_userとはemail情報と捉えて良いのであれば、
      component側で

      this.authService.getUid(); をどっかしらに入れてそれをhtml側で表示させれば問題ないかと思います。

      不明点があればまたご返信ください

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA