Vue+Vant+Koa2+MongoDB 实现用户登陆

前面的文章介绍了Vue+Vant+koa2+MongoDB实现用户注册,今天我们来讲解一下用户登陆的实现。

 

主要实现:

1、前端通过axios向后端发送username、password

2、后端检查用户名是否已注册、比对password是否正确。

3、后端生成JWT令牌返回给前端,前端存储于LocalStorage中。

其中,图形验证码部分将在下一节中讲解。

 

效果截图:

Vue+Vant+Koa2+MongoDB 实现用户登陆

登陆成功,返回code:200 msg: 登陆成功,并打印出token

Vue+Vant+Koa2+MongoDB 实现用户登陆

未注册用户返回:

Vue+Vant+Koa2+MongoDB 实现用户登陆

密码错误返回:

Vue+Vant+Koa2+MongoDB 实现用户登陆

 

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 实现。

 

一、前端部分

于.\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})
  }

 

二、后端部分:

在后端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);
  });
};

 

三、前端储存token

 

方法一:可以直接在axios返回时,用LocalStorage.setItem()将token写入,

LocalStorage.setItem(‘user-token‘,res.token);

这样,我们下次想要访问该token时,直接:

let token = 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;
    } 
  },
}

 

到这里,完整的登陆功能就实现啦。下一节我们会实现图片验证码。

 

如果文章中有错误之处,欢迎大家交流指正。

Vue+Vant+Koa2+MongoDB 实现用户登陆

上一篇:gdb


下一篇:专家解读:利用Angular项目与数据库融合实例