首页 > 其他分享 >怎么实现一个登录页面

怎么实现一个登录页面

时间:2023-08-12 09:56:11浏览次数:49  
标签:info const 登录 实现 loginStore token login 页面

怎么实现一个登录页面

  1. 在api目录下面,建立一个login.js文件, 配置三个发送axios请求的函数并导出

    1. 获取token
    2. 使用token兑换info
    3. 退出登录
    // login.js
    // 获取axios实例request
    import request from '@/util/request';
    
    // 登录,获取token
    const reqLogin = (username, password) =>
      request.post('/admin/login', { username, password });
    
    // 使用token兑换info
    const reqGetInfo = () => request.post('/admin/getinfo');
    
    // 退出登录
    const reqLogout = () => request.post('/admin/logout');
    
    // 导出
    export { reqLogin, reqGetInfo, reqLogout };
    
  2. 在utils目录里面, 创建一个user.js文件夹, 用来存放一些token工具

    1. 添加token
    2. 获取token值
    3. 移除token
    // user.js
    // 添加token
    export function setToken(token) {
      localStorage.setItem('shopAdmin-token', token);
    }
    
    //获取token
    export function getToken() {
      return localStorage.getItem('shopAdmin-token');
    }
    
    // 移除token
    export function removeToken() {
      return localStorage.removeItem('shopAdmin-token');
    }
    
    
  3. 在stores目录下面, 新建一个pinia仓库loginStore.js , 用做登录数据的存储库

    1. state: ①token ②info
    2. actions: ①获取token ②token兑换info ③登出并删除token和info
    // loginStore.js
    import { defineStore } from 'pinia';
    import { setToken, getToken, removeToken } from '@/util/user.js';
    import { reqLogin, reqGetInfo, reqLogout } from '@/api/login.js';
    
    export const useLoginStore = defineStore('login', {
      state: () => {
        return {
          token: getToken() || '',
          info: '',
        };
      },
      actions: {
    
        // 1. 获取token
        async getAndSaveToken({ username, password }) {
          try {
            const { token } = await reqLogin(username, password);
            console.log(token);
            //  存一份到localStorege
            setToken(token);
            //  本仓库存一份
            this.token = token;
          } catch (error) {
            // console.log(error);
            return Promise.reject(error);
          }
        },
    
        //  2.使用token兑换info
        async getInfoByToken() {
          try {
            const info = await reqGetInfo();
            this.info = info || {};
          } catch (error) {
            // console.log(error);
            return Promise.reject(error);
          }
    
        // 3.派发退出登录actions
        logout() {
          // 不在意请求的响应结果
          reqLogout();
          // 清空本仓库的token和info
          this.token = '';
          this.info = {};
          // 清空localStorege
          removeToken();
        },
      },
    });
    
    

    ? 为什么前两个actions都要tryCatch一下, 并返回一个错误的promise?

    这是为了别的页面调用这个actions也能tryCatch处理错误

  4. 在pages目录下面的单文件组件中, 比如login.vue, 在表单验证成功之后, 处理以下逻辑

    1. 表单验证通过
    2. 获取并存储token
    3. 使用token兑换info
    4. 去往首页
    // login.vue
    // 引入登录页的store和vue-router
    import { useLoginStore } from '@/stores/loginStore.js';
    import { useRouter } from 'vue-router';
    // 创建两个对象
    const router = useRouter();
    const loginStore = useLoginStore();
    
    
    ......
    假设上面已经表单校验通过
    
    // 在表单验证成功之后: 
    // 1. 获取并存储token
        try {
          await loginStore.getAndSaveToken({
            username: form.username,
            password: form.password,
          });
        } catch (err) {
          alert('用户名或密码错误');
          return;
        }
    
        //  2. 使用token兑换info
        try {
          await loginStore.getInfoByToken();
        } catch (error) {
          alert('获取用户信息失败');
          return;
        }
    
        // 3. 去往首页
        router.push('/');
    
    
  5. 将token通过请求拦截器, 添加在请求头里面

    1. 引入loginStore

    2. 通过loginStore获取token

    3. 将token添加在请求头中

      注意 :尽量从pinia仓库获取token和info数据, 从localStorege获取性能很差

    import { useLoginStore } from '@/stores/loginStore.js';
    
    ......
    
    request.interceptors.request.use((config) => {
      const token = useLoginStore().token;
      if (token) {
        // 将token设置在请求头中
        config.headers.token = token;
      }
      return config;
    });
    
    ......
    
  6. 配置全局前置守卫

    1. 定义白名单
    2. 从loginStore里面获取token和info
    3. 根据不同情况, 定义不同规则
    // 定义白名单页面数组
    const whiteList = ['/login'];
    
    router.beforeEach(async (to, from, next) => {
      // 引入登录的store
      const loginStore = useLoginStore();
      // 得到token和info里面的username
      const token = loginStore.token;
      const username = loginStore.info.username;
      // 如果没有token
      if (!token) {
        // 是白名单的页面
        if (whiteList.includes(to.path)) {
          // 放行
          next();
        } else {
          // 不是白名单页面, 直接回到登录页
          alert('请登录!');
          next('/login');
        }
      } else {
        // 如果有token, 想从别的页面去login
        if (to.path == '/login') {
          // 不让去登录页
          alert('不可直接去登录页,请先退出登录');
          next(false);
        } else {
          // 如果去的不是登录页
          // 如果有info信息
          if (username) {
            next();
          } else {
            try {
              // 如果没有info信息, 派发actions让仓库重新获取info
              await loginStore.getInfoByToken();
              next();
            } catch (error) {
              // 获取失败,视为token过期
              // 派发退出登录action
              loginStore.logout();
              alert('登录状态过期,请重新登录');
              next('/login');
            }
          }
        }
      }
    });
    

上述的路由规则逻辑如下

标签:info,const,登录,实现,loginStore,token,login,页面
From: https://www.cnblogs.com/liucx955/p/project-q-a-zkifo1.html

相关文章

  • antd vue 解决a-select下拉菜单跟随页面滚动
    问题描述:antd a-select下拉菜单会跟着滚动一块走 官方原话:getPopupContainer菜单渲染父节点。默认渲染到body上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位  解决方案:这样就ok了 :getPopupContainer="triggerNode=>triggerNode.parentNode"......
  • 基于FFT傅里叶变换的64QAM基带信号频偏估计和补偿算法FPGA实现,包含testbench和matlab
    1.算法仿真效果本系统进行了Vivado2019.2平台的开发,并使用matlab2022a对结果进行星座图的显示:    将FPGA的频偏基带QPSK信号和频偏补偿后的QPSK基带信号使用matlab显示星座图,结果如下:   2.算法涉及理论知识概要        FFT傅里叶变换是一种高效的......
  • 使用 Spring 实现控制反转和依赖注入
    概述在本文中,我们将介绍IoC(控制反转)和DI(依赖注入)的概念,以及如何在Spring框架中实现它们。什么是控制反转?控制反转是软件工程中的一个原则,它将对象或程序的某些部分的控制权转移给容器或框架。我们最常在面向对象编程的上下文中使用它。与传统编程相比,传统编程中我们的自定义代......
  • C++实现一键关闭桌面
    方法一:C++关闭桌面,explorer.exe#include<Windows.h>#include<TlHelp32.h>#include"resource.h"#pragmawarning(disable:4996)voidtaskkill(constchar*name){ HANDLEinfo_handle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//拍摄系统中所有进......
  • 微信登录_导入小程序代码
        ......
  • Socket客户端实现
    1importsocket#1.导入内置的socket模块23#2.创建Socket对象4client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)56#3.连接服务器7server_address=('localhost',18080)8client_socket.connect(server_address)910try:1......
  • 【源码解析】postgresql having clause 是如何实现的 (2)
    在上一篇中,主要探究了postgresql源码层面是怎么实现聚合函数的。本篇将探究havingclause是如何实现的。setupcreatetablefoo(aint,bint);insertintofooselectrandom()*i/2,random()*ifromgenerate_series(10,20)g(i);selecta,count(b)fromfoogrou......
  • 不使用循环语句用if和else实现循环
    如果不使用循环语句,可以使用递归函数来实现循环的效果。递归函数是指在函数内部调用自身的函数。下面是一个使用递归函数来实现循环的示例:(初学者记得写include,这里是个普通函数,所以我没写)defloop(count):ifcount<5:ifcount%2==0:......
  • 三子棋的实现
    1.game.h头文件#defineROW3#defineCOL3#include<stdio.h>#include<stdlib.h>#include<time.h>//初始化棋盘voidinit(charboard[ROW][COL],introw,intcol);//打印棋盘voiddisplayboard(charboard[ROW][COL],introw,intcol);//玩家下棋voidplayermove(......
  • Flutter实现将base64解码为image格式,并展示到页面上
    在Flutter中,你可以使用Image.memory来将Base64解码为图像并将其显示在页面上。下面是一个将Base64解码为图像并展示的示例代码:import'dart:convert';import'package:flutter/material.dart';classBase64ImageextendsStatelessWidget{finalStringbase64String;Bas......