zoukankan      html  css  js  c++  java
  • Vue + Vant + Koa2 + MongoDB 实现用户登陆

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

    主要实现:

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

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

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

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

    效果截图:

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

    未注册用户返回:

    密码错误返回:

    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-mobilemallsrc 新建 Login.vue,采用 Vant 的表单控件 :

    <template>
      <div id="login">
        <van-form>
          <van-field v-model="username" label="账号" />
          <van-field v-model="password" type="password" label="密码" />
          <van-button square block type="info" native-type="submit" size="normal" @click="Login"> 登陆 </van-button>
    </van-form>
    </div> </template> <script> import { Field } from 'vant'; import { Button } from 'vant'; import { Toast } from 'vant'; import { Form } from 'vant'; import ajax from '@/api';
    export
    default { components:{ [Field.name]: Field, [Button.name]: Button, [Toast.name]: Toast, [Form.name]: Form, }, data() { return { username:'', password:'', } } } </script>

    mothods 中添加 Login() 方法:

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

    在 srcapiindex.js 中添加,通过 axios 将 username、password 发送到后端接口:

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

    二、后端部分:

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

    在 serviceuserService 中添加处理登陆方法 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 令牌,utilsjwt.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, JSON.stringify(userToken));

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

    JSON.parse(localStorage.getItem(USER_TOKEN))

    不过我们应该熟悉 Vuex 状态管理,为后续开发中大型应用做准备,方法二:

     在 axios 返回时,调用 this.$store.commit()

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

    setUserToken 位于 .srcstoreindex.js :

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

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

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

  • 相关阅读:
    hdu 2569
    hdu 2571
    hdu 4540
    Linux:远程到linux的图形界面
    Windows:文件服务器,访问进去不能查看到完整的文件
    Linux:去除认证,加速 SSH登录
    Linux:永久修改网卡的MAC地址
    Loadrunner:LR提交JSON格式的POST请求
    Linux: vi 编辑器中文乱码
    自动化测试相关:Android SDK无法下载问题,不FQ的解决办法
  • 原文地址:https://www.cnblogs.com/Fcode-/p/13163196.html
Copyright © 2011-2022 走看看