iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 21
0
Modern Web

ngrx/store 4 學習筆記系列 第 21

[ngrx/store-21] Angular 網站實例 - 記得我之二篇

Angular 網站實例 - 記得我之二篇

今天開始 今天完成
後端開始 後端完成

前面完成了讓前端記住我的功能,但在實作的過程中,我們要的可能不只是登入狀態,今天讓我們來看一個例子。

假設我們要讓前端也記住登入使用者的名稱(或者其他資訊),我們又不要直接用明碼將這個資訊放在 localstorage 中,希望將有些資訊放在 token 中,因為 token 是亂碼,一般人是無法解讀的,也無法竄改。

這個資訊還是要透過後端來解析,因為後端才有解這個 token 的鑰匙 (SECRET),我們先來做這個部分

後端加入解析 token 函數

直接看程式

/* get user from token */
router.post('/currentUser', (req, res) => {
  var token = req.body.token;
  if (token) {
    jwt.verify(token, SECRET, function (err, decoded) {
      if (err) {
        res.status(400).send({ success: false})
      } else {
        res.send({success: true, payload: decoded.username});
      }
    })
  } else {
    res.status(400).send({ success: false, payload: 'no token'});
  }
})

之前我們用 let token = jwt.sign({ username: username}, SECRET, {'expiresIn': '1h'} ); 來將使用者名稱包進 token 裡,這裡我們就可以用 jwt.verify(token, SECRET, function (err, decoded) {} 來解析 token, 解析成功的話就送回 decoded.username給前端,這樣前端就可以來使用這個 API。

實際上,我們通常會將 user id 放在 token 裡,後端接到 id 後會到資料庫找出對應資料,再傳給前端,這裡為了簡單起見,不使用到資料庫,直接帶出資料。

前端修改使用者服務

回到前端的使用者服務,我們加入一個新的服務,getUser(),程式如下

 // get user from server
    getUserFromServer(): Observable<User> {
        if (!this.utils.isTokenExpired()) {
            const token = this.utils.getToken();
            return this.http.post(this.appConfig.apiUrl + '/users/currentUser', { 'token': token })
                .map((res: Response) => {
                    if (res.success) {
                        return res.payload;
                    } else {
                        return null;
                    }
                })
        } else {
            return of(null);
        }
    }

    getUser() {
        this.getUserFromServer()
            .subscribe(res => {
                this.currentUser$.next(res);
            },
            (err: HttpErrorResponse) => {
                if (err.error instanceof Error) {
                    console.log('client-side error');
                } else {
                    console.log('server-side error');
                }
            })
    }
  1. getUser() 呼叫 getUserFromServer()
  2. getUserFromServer()使用 HttpClient 來向後端連結,成功的話回傳一個 Observable<User>getUser()
  3. getUser() 將它放進 currentUser$ 這個BehaviorSubject, push 給 subscribers,對了,習慣上我們會在 Observable 的變數後加入 '$',使用上會更清楚。

修改 checkUser()

記得前面在 startup.service.ts 中,我們會呼叫 使用者服務的 checkUser()

//... 省略
    load(): Promise<any> {
        return new Promise((resolve, reject) => {
            return this.userService.checkUser()
                .subscribe(res => {
                    if (res) {
            //...

所以我們可以將 getUser() 放進這個函數中,這樣在瀏覽器重新刷的時候就會順便帶進我們要的資料,程式如下

   // when startup
    checkUser(): Observable<boolean> {
        if (!this.utils.isTokenExpired()) {
            this.loginStatus$.next(true);
            this.getUser();
            return of(true);
        } else {
            console.log('no token or token is expired');
            this.utils.removeToken();
            return of(false);
        }
    }

現在如果登入後,回到首頁,重新刷瀏覽器,應該會得到下面的截圖,也就是跟之前一樣的畫面
https://ithelp.ithome.com.tw/upload/images/20180106/20103574ohEVMgheHj.png

至此,我們完成了使用 Angular 的服務來連結後端,完成使用者登入的功能,也儲存了使用者登入的狀態以及一些資訊,回顧一下使用者狀態

  1. 當系統開始時,使用者是未登入狀態
  2. 使用者登入後,狀態為登入狀態
  3. 當使用者重刷瀏覽器,而 token 還沒過期時,這時為登入狀態
  4. 當 token 過期時,這時為未登入狀態
  5. 我們每五分鐘檢查一次,如果 token 過期,我們會將狀態變為未登入狀態

接下來,我們要完成會員功能,也就是登入狀態下的會員,可以到會員專屬頁面來看報告


上一篇
[ngrx/store-20] Angular 網站實例 - 記得我篇
下一篇
[ngrx/store-22] Angular 網站實例 - 會員篇之後端
系列文
ngrx/store 4 學習筆記30

尚未有邦友留言

立即登入留言