Vue+Vant+Koa2+MongoDB 實現用戶登錄

前面的文章介紹了Vue+Vant+koa2+MongoDB實現用戶註冊,今天咱們來說解一下用戶登錄的實現。前端

 

主要實現:vue

一、前端經過axios向後端發送username、passwordios

二、後端檢查用戶名是否已註冊、比對password是否正確。web

三、後端生成JWT令牌返回給前端,前端存儲於localStorage中。ajax

其中,圖形驗證碼部分將在下一節中講解。數據庫

 

效果截圖:json

登錄成功,返回code:200 msg: 登錄成功,並打印出tokenaxios

未註冊用戶返回:後端

密碼錯誤返回:api

 

JWT簡介:

JWT全稱JSON WEB TOKEN,是目前最流行的跨域認證解決方案,假設用戶登錄成功以後,首先訪問A頁面,而後訪問B頁面,而這兩個頁面的內容都須要根據用戶的身份來獲取,好比說A頁面爲用戶的訂單列表,須要根據user_id來查詢該用戶的全部訂單,B頁面爲用戶的收貨地址列表,又須要根據user_id字段來查詢該用戶的地址列表,而在不一樣頁面之間,這個user_id是如何傳遞的呢,首先咱們能夠利用session,服務端經過cookie將session發送給客戶端,這種方式是將session存儲於服務端,還有一種方式就是服務端經過jwt將user_id、username等信息生成加密的token,客戶端接收以後將其存儲於LocalStroage,這樣當用戶訪問B頁面地址時,配置請求的header訪問頭,將token添加進請求頭,服務端收到token進行解析,便可解析出user_id、username等信息,從而獲取出user_id,從而B頁面就會根據user_id獲取到該用戶的地址列表。

 

 另外,cookie方式不支持跨域,JWT支持跨域認證,例如單點登陸就是依靠JWT 實現。

 

1、前端部分

於.\vue-mall-mobile\mall\src 新建 Login.vue,仍然採用Vant的輸入框控件:

<template>
  <div id="login">
    <van-cell-group>
      <van-field v-model="username" label="帳號" />
      <van-field v-model="password" type="password" label="密碼" />
    </van-cell-group>
    <van-button square block type="info" native-type="submit" size="normal" @click="Login">
      登錄
    </van-button>
  </div>
</template>

<script>
  import { Field } from 'vant';
  import { Button } from 'vant';
  import { Toast } from 'vant';
  import { Cell, CellGroup } from 'vant';
  import ajax from '@/api';  
export
default { components:{ [Field.name]: Field, [Button.name]: Button, [Toast.name]: Toast, [Cell.name]: Cell, [CellGroup.name]: CellGroup, }, data() { return { username:'', password:'', } } } </script>

 

mothods中添加Login()方法:

async Login() {
  let { username, password} = this.$data;
  let res = await ajax.login(username, password);
  console.log(res)
}

 

在src\api\index.js中添加,經過axios將username、password發送到後端接口:

login(username = '', password = '') {
    return axios.post('localhost:3000/users/loginUser',{username, password})
  }

 

2、後端部分:

在後端routes\users.js中添加響應路由:

/**
 * 用戶登錄
 */
router.post('/loginUser', async function (ctx) {
  let {username, password} = ctx.request.body;
  
  if(!username || !password) return ctx.body = {code: 4020,msg: '請填寫完整的註冊信息'};
  
  let args = {username, password};
  const userData = await userService.accountLogin(args);
  
  ctx.body = (userData.code === 200) 
     ? {code: 200, msg: '登錄成功', token: jwt._createToken(userData)} 
     : userData
})

 

在service\userService中添加處理登錄方法 accountLgoin({username, password}):

async accountLogin({username, password}) {
    const userDoc = await UserModel.findOne({username});
    if(!userDoc) return {code: 0, msg: '該用戶還沒有註冊'};
    
    let result = await userDoc.comparePassword(password, userDoc.password); // 進行密碼比對是否一致
    return !result
      ? { code: -2, msg: '密碼不正確' }
      : {
          code: 200,
          _id: userDoc._id,
          userName: userDoc.userName,
          gender: userDoc.gender,
          avatar: userDoc.avatar, 
          mobilePhone: userDoc.mobilePhone,
          email: userDoc.email,
          year: userDoc.year,
          month: userDoc.month, 
          day: userDoc.day
        };
  }

 這裏的userDoc.comparePassword()方法,是咱們在定義UserModel是添加的方法,bcryptjs的bcrypt.compare()方法來實現對比咱們在輸入框中輸入的祕密和保存在數據庫裏的hash處理後的密碼。

 

生成JWT令牌,\utils\jwt.js中的_createToken()方法:

const jwt = require('jsonwebtoken');
/**
 * 建立 Token
 */
const _createToken = (userInfo) => {
  // JWT 格式 token | 有效時間 1 小時
  return jwt.sign({ userInfo }, secret, { expiresIn: '1h' });
};

 

這裏的 {userInfo} 存儲了用戶的id、username、性別等信息,以token令牌的方式存儲於客戶端,也就是前端,等到客戶端發送請求時,在header請求頭中,加入該token,後端經過jwt.virefy()將token中存儲的信息解析出來,解析方法以下,從而使後端代碼能夠經過解析出來的信息認定用戶的身份。

const _verify = (token) => {
  return jwt.verify(token, secret, (error, decoded) => {
      console.log(decoded);
  });
};

 

3、前端儲存token

 

方法一:能夠直接在axios返回時,用localStorage.setItem()將token寫入,

localStorage.setItem(USER_TOKEN, JSON.stringify(userToken));

這樣,咱們下次想要訪問該token時,直接:

JSON.parse(localStorage.getItem(USER_TOKEN))

 

不過咱們應該熟悉Vuex狀態管理,爲後續開發中大型應用作準備,方法二:

 在axios返回時,調用this.$store.commit()

(res.token)&&(this.$store.commit('setUserToken', res.token));

 

setUserToken位於.\src\store\index.js:

export default new Vuex.Store({
  state: {
    token: '',
  },
  mutations: {
    setUserToken(state, token) {
      alert(token);
      state.token = token;
    } 
  },
}

 

到這裏,完整的登錄功能就實現啦。下一節咱們會實現圖片驗證碼。

 

若是文章中有錯誤之處,歡迎你們交流指正。

相關文章
相關標籤/搜索