vue基于Cookies实现记住密码自动登录功能

news2024/12/28 22:59:41

vue基于Cookies实现记住密码自动登录功能

Cookies 和localStorage存储比对

实现记住密码功能时,使用 Cookies 和使用 localStorage 各有其优势和考虑因素,具体需要取决于需求和安全考量:
在这里插入图片描述

1、Cookies 的优势:

  1. 广泛支持:Cookies 是 HTTP 协议的一部分,因此在几乎所有的浏览器和 Web 应用程序中都有良好的支持。
  2. 服务器端处理:可以通过设置 Cookie 的过期时间来实现自动登录功能,因为浏览器会在过期时间之前自动发送该 Cookie。这使得记住密码的实现变得相对简单。
  3. 可配置性:可以通过设置 Cookie 的属性(如过期时间、域名、路径等)来控制其在不同情况下的行为,例如只在 HTTPS 连接中发送、只在特定域名下可用等。
  4. 与服务器端状态同步:在某些情况下,特别是涉及到跨站点状态共享或服务器端状态跟踪时,Cookies 可以更自然地与服务器端的状态同步。

2、localStorage 的优势:

  1. 本地存储:localStorage 存储在用户的浏览器中,相比于 Cookies,更难以通过网络请求访问,从而提供了更好的安全性。
  2. 容量较大:localStorage 的存储容量通常比 Cookies 大得多(大约5MB左右),这使得它更适合存储大量的用户信息或配置数据。
  3. 更简单的 API:使用 localStorage 比起操作 Cookies 更加简单和直观,因为它提供了简洁的 key-value 存储接口。

3、综合考虑:

  • 安全性:对于敏感数据如密码,localStorage 通常被认为比 Cookies 更安全,因为它不会在每个 HTTP 请求中自动发送给服务器。
  • 便捷性:Cookies 更适合需要与服务器端状态同步或通过 HTTP 请求进行状态管理的场景,而 localStorage 更适合客户端本地的长期数据存储。
  • 合规性:在 GDPR 等隐私法规的要求下,需要谨慎处理用户数据。Cookies 的使用受到更严格的监管和规范。

综上所述,选择使用 Cookies 还是 localStorage 实现记住密码功能取决于具体需求,特别是安全性、数据大小和与服务器的交互方式等方面的考量。

4、用户登录信息加密

因为每个 Cookie 的大小限制在 4KB 到 8KB 之间。这包括了 Cookie 的名称、值以及其他元数据(如域名、路径、过期时间等)。浏览器对单个域名可以存储的 Cookie 数量也有限制,通常在几百个到几千个之间。

所以对用户信息进行前端cookies进行存储时,需要提取关键信息,此方案实现只对用户密码进行公钥加密,对用户其他的非关键信息进行自定义加密函数

5、主要加密函数示例

// auth.js
import Cookies from 'js-cookie';
import CryptoJS from 'crypto-js';
const Base64 = require('js-base64').Base64;
const EncryptionKey = 'encryptionKey';
// 加密
export const encrypt = word => {
  if (word == '' || word === undefined) {
    return '';
  }
  word = Base64.encode(word);
  var key = CryptoJS.enc.Utf8.parse(EncryptionKey);
  var srcs = CryptoJS.enc.Utf8.parse(word);
  var encrypted = CryptoJS.AES.encrypt(srcs, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  });
  return Base64.encode(encrypted.toString());
};

// 解密
export const decrypt = word => {
  if (word == '' || word === undefined) {
    return '';
  }
  word = Base64.decode(word);
  var key = CryptoJS.enc.Utf8.parse(EncryptionKey);
  var decrypt = CryptoJS.AES.decrypt(word, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  });
  return Base64.decode(CryptoJS.enc.Utf8.stringify(decrypt).toString());
};

export function setCookie(name, value = '', seconds) {
  let expires = new Date(new Date() * 1 + seconds * 1000);
  Cookies.set(name, value, { expires });
}

export function getCookieByName(name) {
  return Cookies.get(name);
}

// 设置记住密码信息
export function setRememberInfo(info) {
  const newInfo = JSON.parse(JSON.stringify(info));
  const ecKey = 'abcdefg1234567xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // 公钥加密KEY
  newInfo.pwd = encryptFn(ecKey, newInfo.pwd);
  const encryptInfo = encrypt(JSON.stringify(newInfo));
  setCookie('rememberInfo_' + newInfo.deptId, encryptInfo, 2592000);
}

// 公钥密码加密
export function encryptFn(publicKey, data) {
  const crypto = require('crypto');
  // 使用公钥加密
  const publicKeyStr = '-----BEGIN PUBLIC KEY-----\n' + publicKey + '\n' + '-----END PUBLIC KEY-----';
  const encryptStr = crypto.publicEncrypt(
    { key: publicKeyStr, padding: crypto.constants.RSA_PKCS1_PADDING },
    Buffer.from(data, 'utf8')
  );
  const encrypted = encryptStr.toString('base64');
  return encrypted;
}

6、逻辑处理

1、在用户登录判断是否选了记住密码,如果勾选进行正常流程登录,并将用户信息记录用加密函数对主要信息进行信息加密存储在cookies中,看需要设置过期时间等其他cookies配置项。

2、用户重新进入登录页时、判断cookies中是否存在对应的用户信息,如果存在进行解密。拿出用户信息。

3、拿到的用户信息存在公钥加密的关键信息,比如用户密码,需要后端提供接口传递用户信息参数,后端使用私钥解密,校验用户信息是否匹配。如果匹配,一般接口返回包含token的成功响应。

4、已经拿到token了,就可以进行正常登录的后续流程实现自动登录了。

5、退出登录时,需要清除对应Cookies。

7、自动登录流程图

file

8、完整代码示例

只包含关键处理

<template>
  <!-- 登录首页 -->
  <div>
    <!-- 登录表单 -->
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" auto-complete="on" label-position="left">
      <el-form-item prop="userName">
        <el-input placeholder="请输入用户名" v-model="loginForm.userName">
          <i slot="prefix" class="el-input__icon iconfont icon-yonghu-filled"></i>
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input placeholder="请输入密码" type="password" v-model="loginForm.password">
          <i slot="prefix" class="el-input__icon iconfont icon-mima-filled"></i>
        </el-input>
      </el-form-item>
      <el-form-item prop="captcha" v-if="captchaType == '2'">
        <el-input placeholder="请输入验证码" v-model="loginForm.captcha" maxlength="10">
          <i slot="prefix" class="el-input__icon iconfont icon-yanzheng-filled"></i>
          <img class="image_code" slot="suffix" :src="verifyKey" alt />
        </el-input>
      </el-form-item>
    </el-form>
    <div>
      <el-checkbox v-model="isRemember">记住密码</el-checkbox>
    </div>
    <el-button type="primary" @click.prevent="loginRequest()">登录</el-button>
  </div>
</template>

<script>
import { loginRequest } from '@/api/user';
import { setToken, decrypt, encrypt, setRememberInfo } from '@/utils/auth';
import { getLoginInfoByRember } from '@/api/public/index';

export default {
  data() {
    return {
      deptId: null,
      loginForm: {
        userName: '',
        password: '',
        captchaKey: '',
        captcha: '',
        keyId: ''
      },
      loginRules: {
        userName: [{ required: true, trigger: 'blur', message: '请输入用户名' }],
        password: [{ required: true, trigger: 'blur', message: '请输入密码' }]
      },
      publicKey: null,
      isRemember: false, //是否勾选记住密码
      userParams: {} // 需要存储的登录信息
    };
  },
  created() {
    this.deptId = this.$route.query.deptId;
    const rmInfo = this.getCookieByName('rememberInfo_' + this.deptId);
    if (rmInfo) {
      this.isRemember = true;
      this.getRememberInfo(rmInfo);
    }
  },
  methods: {
    // 根据记住密码获取登录信息
    getRememberInfo(remberInfo) {
      remberInfo = JSON.parse(decrypt(remberInfo));
      this.loginForm.userName = remberInfo.userName;
      const params = {
        userName: remberInfo.userName,
        password: remberInfo.pwd, // remberInfo.pwd是使用公钥加密的
        deptId: this.deptId
        // ......
      };
      getLoginInfoByRember(params) // 此请求接口为后端提供、对前端加密的密码进行验证
        .then(res => {
          // 校验成功、处理登录逻辑
          // 一般返回携带Token的响应,例如{ result:token:"2e7d220f2f60492b8835189d2d6f3463", .... }
          this.loginAfterOperate(res);
        })
        .catch(error => {
          // 校验失败、处理失败逻辑
          this.loginErrorOperate(error);
        });
    },
    // 获取加密key
    initKey() {
      return initKey().then(res => {
        if (res.code === 1000) {
          this.publicKey = res.result.publicKey;
        }
      });
    },
    // 正常登录处理
    async loginRequest() {
      await this.initKey();
      const params = {
        userName: this.loginForm.userName.trim(),
        password: encrypt(this.publicKey, this.loginForm.password)
        // 其他登录参数......
      };
      loginRequest(params)
        .then(res => {
          if (this.isRemember) {
            this.userParams = { ...params, pwd: this.loginForm.password };
            setRememberInfo(this.userParams); // 存储用户登录信息Cookies
          }
          this.loginAfterOperate(res);
        })
        .catch(error => {
          this.loginErrorOperate(error);
        });
    },
    // 统一登录后处理
    async loginAfterOperate(res, params = null) {
      const { code, result } = res;
      if (code == 1000) {
        setToken(result.token);
        // 后续登录逻辑......
      }
    },
    // 统一登录异常处理
    async loginErrorOperate(error) {
      this.$message({ showClose: true, message: error.message, type: 'error', offset: 100 });
      // 其他逻辑......
    }
  }
};
</script>

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中介者模式详解:概念、优点及实例

目录 中介者模式中介者模式结构中介者模式适用场景中介者模式优缺点练手题目题目描述输入描述输出描述题解 中介者模式 中介者模式是一种行为设计模式&#xff0c; 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互&#xff0c; 迫使它们通过一个中介者…

windows ssh的登录,私钥权限太开放 WARNING: UNPROTECTED PRIVATE KEY FILE!

问题描述 ssh -i wang -D localhost:1080 wangsg.ks99.topBad permissions. Try removing permissions for user Permissions for xxx are too open. F:\pms\pms-gpg-key\ssh-key\wang>ssh -i wang -D localhost:1080 wangsg.ks99.top Bad permissions. Try removing perm…

查看公网IP的网络出口

文章目录 背景 背景 有时候在各种交易或其他时候&#xff0c;会被问到给我一个公网IP&#xff0c;我来帮你加白名单。 这个怎么怎么获取公网IP呢&#xff0c;在自己本机查看ipconfig或者ifconfig ip a 等命令查到的一般都是局域网的IP&#xff0c;每台机器都需要一个IP来进行对…

【文档智能 RAG】RAG新基建-RAG性能增强关键技术点及通用文档解析工具-TextIn

前言 在私有领域知识问答和企业知识管理领域&#xff0c;结合检索增强型生成模型&#xff08;Retrieval-Augmented Generation, RAG&#xff09;大模型&#xff08;Large Language Model, LLM&#xff09;已成为一种趋势。然而&#xff0c;在RAG系统的文档预处理阶段和检索阶段…

【Elasticsearch7】3-基本操作

目录 RESTful 数据格式 HTTP操作 索引操作 倒排索引 创建索引 查看所有索引 查看单个索引 删除索引 文档操作 创建文档 查看文档 ​编辑 全量修改 ​编辑局部修改 删除文档 条件删除文档 高级查询 条件查询 URL带参查询 请求体带参查询 带请求体方式的查…

STM32的ADC详解

目录 一、ADC简介 二、ADC的时钟 三、ADC特性 四、ADC功能说明 五、规则通道和注入通道 1.规则通道 2.注入通道 3.区别 六、数据寄存器 1.右对齐 2.左对齐 七、转换模式 1.单次转换模式 2.续转换模式 3.扫描模式 4.区别 八、程序实现 1.需求 2.ADC初始化 3.A…

InfiniBand网络-赋能高性能计算的卓越引擎

InfiniBand&#xff1a;赋能高性能计算网络的卓越引擎 InfiniBand作为一种先进的内网计算平台&#xff0c;已成为驱动高性能计算&#xff08;HPC&#xff09;、人工智能&#xff08;AI&#xff09;以及超大规模云基础设施演进的核心力量&#xff0c;其展现出无可比拟的性能优势…

mongodb数据导出与导入

一、先去检查mongodump mongodump --version 如果报 mongodump version: built-without-version-string 或者其他的较老的版本&#xff0c;直接去下载最新的【传送门】 【以Ubuntu18.04为例】 安装工具 假设你下载的是 .tgz 文件&#xff08;适用于 Linux 系统&#xff09;&am…

Java中SPI机制原理解析

使用SPI机制前后的代码变化 加载MySQL对JDBC的Driver接口实现 在未使用SPI机制之前&#xff0c;使用JDBC操作数据库的时候&#xff0c;一般会写如下的代码&#xff1a;// 通过这行代码手动加载MySql对Driver接口的实现类 Class.forName("com.mysql.jdbc.Driver") Dr…

鸿蒙开发error: failed to start ability

鸿蒙开发项目编译过后不能启动 项目在模拟器运行报&#xff1a; error: failed to start ability. Error while Launching ability 解决办法&#xff1a; 1&#xff0c;看了一些文章说是把module.json5配置文件中的"exported"由false改成true&#xff0c;没有解…

Python 实现股票指标计算——BIAS

BIAS (Bias Ratio) - 乖离率 1 公式 BIAS (当日收盘价 - N日平均收盘价) ➗ N日平均收盘价 ✖ 100&#xff05; N一般取6、12、24 2 数据准备 我们以科创50指数 000688 为例&#xff0c;指数开始日期为2019-12-31&#xff0c;数据格式如下&#xff1a; 3 计算过程 def c…

Java 中的异常

异常&#xff1a;就是出现的问题。 在Java中异常被当成对象进行处理&#xff0c;所有的异常类都继承于Throwable类&#xff0c;如果Java提供的异常类并不能满足需求&#xff0c;用户还可以自己定义一个异常类。 下面是异常体系结构&#xff1a; Throwable又分成了Error和Exce…

《无所不能的JavaScript · 对象简介》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

OpenStack Yoga版安装笔记(七)glance练习补充

1、练习场景说明 在OpenStack Yoga版安装笔记&#xff08;五&#xff09;中&#xff0c;glance已经在controller node虚拟机上安装完成&#xff0c;并且已经成功拍摄了快照。 此时&#xff0c;controller node虚机已经安装了keystone、keystone DB、glance、glance DB、OpenSta…

利用【MATLAB】和【Python】进行【图与网络模型】的高级应用与分析】

目录 一、图与网络的基本概念 1. 无向图与有向图 2. 简单图、完全图、赋权图 3. 顶点的度 4. 子图与连通性 5. 图的矩阵表示 MATLAB代码实例 Python代码实例 二、最短路径问题 1. 最短路径问题的定义 2. Dijkstra算法 MATLAB代码实例 Python代码实例 三、最小生…

昇思MindSpore学习总结十七 —— 基于MindSpore通过GPT实现情感分类

1、要求 2、导入了一些必要的库和模块 以便在使用MindSpore和MindNLP进行深度学习任务时能使用各种功能&#xff0c;比如数据集处理、模型训练、评估和回调功能。 import os # 导入操作系统相关功能的模块&#xff0c;如文件和目录操作import mindspore # 导入MindSpore库&a…

入门C语言只需一个星期(星期六)

点击上方"蓝字"关注我们 01、创建结构体 struct MyStructure { // 结构声明 int myNum; // 成员&#xff08;int 变量&#xff09; char myLetter; // 成员&#xff08;char 变量&#xff09;}; // 用分号结束结构创建一个名为 s1 的结构变量​struct myStru…

# Redis 入门到精通(九)-- 主从复制(1)

Redis 入门到精通&#xff08;九&#xff09;-- 主从复制&#xff08;1&#xff09; 一、redis 主从复制 – 主从复制简介 1、互联网“三高”架构 高并发高性能高可用 2、你的“Redis”是否高可用&#xff1f; 1&#xff09;单机 redis 的风险与问题 问题1.机器故障  现…

kafka服务介绍

kafka 安装使用管理 Kafka Apache Kafka 是一个开源的分布式事件流平台&#xff0c;主要用于实时数据传输和流处理。它最初由 LinkedIn 开发&#xff0c;并在 2011 年成为 Apache 基金会的顶级项目。Kafka 设计的目标是处理大规模的数据流&#xff0c;同时提供高吞吐量、低延迟…

C语言 通讯录管理 完整代码

这份代码&#xff0c;是我从网上找的。目前是能运行。我正在读。有些不懂的地方&#xff0c;等下再记录下来。 有些地方的命名&#xff0c;还需要重新写一下。 比如: PersonInfo* info &address_book->all_address[address_book->size]; 应该改为&#xff1a; Perso…