vue+vite+js后台管理系统:用户登录功能

目录

1. 准备工作

1.1 后端验证接口:使用 express+mongodb 模拟

1.2 注册两个用户

2. Login页面

2.1 使用ant-design-vue搭建一个简易的登录页面 

2.2 给按钮绑定点击事件 

3. 表单验证成功后:发送登录请求

4. 登录成功后操作

5. 最后


1. 准备工作

1.1 后端验证接口:使用 express+mongodb 模拟

// app.js
const express = require('express');
const { User } = require('./mongoose');
const app = express();
const port = 3000;

app.use(express.json())

// post请求
// 注册
app.post('/register', async(req, res)=>{
    const user = await User.create({
        username: req.body.username,
        password: req.body.password,
    })
    res.send(user)
})

// 登录
app.post('/login', async(req, res)=>{
    let user = await User.findOne({
        username: req.body.username
    });
    if(!user){
        return res.status(401).send({
            message: '用户不存在'
        })
    };
    const isValidPassword = await require('bcryptjs').compare(
        req.body.password,
        user.password
    );
    if(!isValidPassword){
        return res.status(401).send({
            message: '密码错误'
        })
    };
    const jwt = require('jsonwebtoken');
    const token = jwt.sign({
        id: String(user.id)
    }, 'express-auth')
    res.send({
        user, token
    })
})

app.listen(port, ()=>{
    console.log(`端口${port}监听中`);
})
// mongoose.js
const mongoose = require('mongoose');
const bcryptjs = require('bcryptjs')
mongoose.connect('mongodb://localhost:27017/express-auth', {
    useNewUrlParser: true
})

const connect = mongoose.connection;
connect.on('connected', ()=>{
    console.log('数据库连接成功');
})

const User = mongoose.model('User', new mongoose.Schema({
    username: {type: String, unique: true},
    password:{type: String, set(val){
        return bcryptjs.hashSync(val, 10)
    }}
}))

//User.db.dropCollection('users')
module.exports = { User }

1.2 注册两个用户

管理员:

username: admin

password: 123

role: ['admin']

超级管理员

username: superadmin

password: 123

role: ['superadmin']

2. Login页面

2.1 使用ant-design-vue搭建一个简易的登录页面 

2.2 给按钮绑定点击事件 

表单验证+跳转

<template lang="">
  <div class="wrapper">
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
    <HelloWorld msg="You did it!" />
  </div>
  <a-form style="text-align: center">
    <a-form-item label="Username" required v-bind="validateInfos.username">
      <a-input v-model:value="userInfo.username"/>
    </a-form-item>
    <a-form-item label="Password" required  v-bind="validateInfos.password">
      <a-input v-model:value="userInfo.password" />
    </a-form-item>
    <a-form-item>
      <a-button @click.prevent="handleLogin">登录</a-button>
    </a-form-item>
  </a-form>
</template>

<script setup>
import HelloWorld from '@/components/HelloWorld.vue'
import { reactive, toRaw } from 'vue'
import { useUserStore } from '@/stores/modules/user'
import { Form } from 'ant-design-vue'

const userStore = useUserStore()

const userInfo = reactive({
  username: '',
  password: ''
})

const useForm = Form.useForm
const { validate, validateInfos } = useForm(
  userInfo,
  reactive({
    username: [{ required: true, message: '请输入用户名' }],
    password: [{ required: true, message: '请输入密码' }]
  })
)

function handleLogin() {
  // 表单验证,成功后跳转
  validate()
    .then(async () => {
      const data = toRaw(userInfo)
      if (data) {
        await userStore.login(data)
      }
    })
    .catch(err=>{
      console.log(err)
    })
}
</script>

3. 表单验证成功后:发送登录请求

注:将用户相关操作写在src/store/userStore中

发请求(登录接口)验证用户名及密码是否正确。错误时会出现相应弹窗。

注:请求使用axios进行二次封装,具体见博客vue + vite + js 项目中 axios的二次封装_sunnakay的博客-CSDN博客,其中错误弹窗在响应拦截器中设置。

4. 登录成功后操作

①保存token到store中,同时保存到客户端的sessionStorage中以保持登录效果。(这里token的保存也有很多值得学习的,大家可以自己上网搜索相关内容)

②获取并保存用户详细信息:可能包括用户id、用户名、用户角色等内容。(注:用户角色涉及到权限管理的内容)

在这里同样使用express+mongodb模拟接口并返回数据,在src/api/user.js中定义发送请求的api,然后在当前文件src/stores/modules/user.js中调用

③动态添加路由表。详情可见另一篇博客:vue + vite + js 后台管理系统:权限控制+路由/菜单动态加载_sunnakay的博客-CSDN博客

④跳转后台主页。

整体代码如下:

import { defineStore } from 'pinia'
import { loginApi, getUserInfo } from '@/api/user'
import { usePermissonStore } from './permission'
import router from '@/router'
import { isArray } from '@/utils/is'

export const useUserStore = defineStore('users', {
  state: () => {
    return {
      userInfo: {},
      token: undefined,
      roleList: []
    }
  },
  getters: {
    getUserInfo(state){
      return state.userInfo || {};
    },
    getToken(state) {
      return state.token || undefined
    }
  },
  actions: {
    setToken(info) {
      this.token = info ? info : ''
      window.sessionStorage.setItem('token',info)
    },

    setRoleList(info) {
      this.roleList = info
      window.sessionStorage.setItem('roleList',info)
    },

    setUserInfo(info) {
      this.userInfo = info
      window.sessionStorage.setItem('userInfo',info)
    },

    async login(params) {
      try {
        // 发请求
        const result = await loginApi(params)
        // 保存token
        const { token, username } = result
        this.setToken(token)
        // 进行登录成功后跳转等工作
        return this.afterLoginAction(username)
      } catch (error) {
        return Promise.reject(error)
      }
    },

    async afterLoginAction() {
      // 获取用户信息
      const userInfo = await this.getUserInfoAction();
      // 动态匹配路由,加载菜单
      const permissionStore = usePermissonStore()
      const routes = await permissionStore.buildRoutesAction()
      routes.forEach((route) => {
        router.addRoute(route)
      })
      // 跳转主页面
      router.push('/dashboard')
      return userInfo
    },

    async getUserInfoAction(){
      const userInfo = await getUserInfo();
      // 对roles的操作要视具体情况而定,看后端返回的数据是怎样的,我这里自己模拟是数组中包含对象
      const { roles = [] } = userInfo;
      if(isArray(roles)){
        const roleList = roles.map((item) => item.value);
        this.setRoleList(roleList)
      }else{
        userInfo.roles = [];
        this.setRoleList([])
      }
      this.setUserInfo(userInfo);
      return userInfo
    }
  }
})

5. 最后

这只是一个整体的粗略框架,还有许多细节的地方需要完善,后续想到什么再做更新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值