Vue项目,前端如何来做登录密码加密传输?

在 Vue 3 前端实现登录密码加密传输,核心目标是防止密码以明文形式在网络中传输(避免被中间人窃听,尽管 HTTPS 是基础,但在高安全要求场景下通常需要应用层二次加密)。

最常见的方案是:前端使用公钥加密密码 -> 后端使用私钥解密 。通常采用非对称加密算法 RSAECC

以下是基于 Vue 3 + TypeScript + rsaencrypt (或 jsencrypt) 的完整实现方案。

1. 核心流程设计

  1. 后端生成密钥对:后端生成 RSA 公钥和私钥。
  2. 获取公钥 :前端在登录页面加载时(或用户点击登录前),调用接口获取后端的公钥(也可以由后端定期轮换,通过接口下发)。
  3. 前端加密 :用户使用 jsencryptnode-rsa 等库,利用公钥对密码进行加密。
  4. 发送请求:将加密后的密文(通常是 Base64 字符串)发送给后端。
  5. 后端解密:后端使用私钥解密密文,得到原始密码,再进行哈希比对(如 BCrypt/Argon2)验证登录。

2. 前置准备

安装加密库。推荐使用 jsencrypt (轻量,专为浏览器设计) 或 encryptlong (如果密码很长,标准 RSA 有长度限制,但密码通常很短,jsencrypt 足够)。

javascript 复制代码
npm install jsencrypt
# 或者
yarn add jsencrypt

3. Vue 3 代码实现

步骤一:创建加密工具类 (src/utils/rsaEncrypt.ts)

封装加密逻辑,方便复用。

javascript 复制代码
// src/utils/rsaEncrypt.ts
import JSEncrypt from 'jsencrypt';

// 注意:实际项目中,公钥通常从后端接口动态获取,而不是写死在这里
// 这里为了演示,先假设有一个默认公钥,实际请看步骤二中的动态获取
const DEFAULT_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD... (你的后端公钥) ...==
-----END PUBLIC KEY-----`;

/**
 * 使用公钥加密字符串
 * @param text 待加密的明文(密码)
 * @param publicKey 公钥,如果不传则使用默认值(建议动态传入)
 */
export function encryptPassword(text: string, publicKey?: string): string {
  const encryptor = new JSEncrypt();
  // 设置公钥
  encryptor.setPublicKey(publicKey || DEFAULT_PUBLIC_KEY);
  
  // 执行加密
  const encrypted = encryptor.encrypt(text);
  
  if (!encrypted) {
    throw new Error('密码加密失败');
  }
  
  return encrypted;
}
步骤二:在登录组件中使用 (src/views/Login.vue)

在实际场景中,强烈建议在登录页初始化时调用后端接口获取最新的公钥,以防重放攻击或密钥轮换。

javascript 复制代码
<template>
  <div class="login-container">
    <h2>用户登录</h2>
    <form @submit.prevent="handleLogin">
      <div class="form-item">
        <label>用户名:</label>
        <input v-model="loginForm.username" type="text" required />
      </div>
      
      <div class="form-item">
        <label>密码:</label>
        <!-- 输入框本身可以是 type="password" 隐藏显示,但这不影响传输加密 -->
        <input v-model="loginForm.password" type="password" required />
      </div>

      <button type="submit" :disabled="loading">
        {{ loading ? '登录中...' : '登录' }}
      </button>
    </form>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { encryptPassword } from '@/utils/rsaEncrypt';
// 假设你有一个 axios 实例
import request from '@/utils/request'; 

const loading = ref(false);
const publicKey = ref<string>('');

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

// 1. 页面加载时获取后端公钥
const fetchPublicKey = async () => {
  try {
    // 模拟接口:/api/auth/public-key
    const res = await request.get('/auth/public-key');
    // 假设后端返回格式 { code: 200, data: "-----BEGIN PUBLIC KEY-----..." }
    publicKey.value = res.data; 
    console.log('公钥已获取');
  } catch (error) {
    console.error('获取公钥失败', error);
    // 降级策略:如果获取失败,是否允许登录?通常高安场景应禁止
  }
};

// 2. 处理登录
const handleLogin = async () => {
  if (!loginForm.username || !loginForm.password) {
    alert('请输入用户名和密码');
    return;
  }

  if (!publicKey.value) {
    alert('系统安全组件未加载,请稍后重试');
    return;
  }

  loading.value = true;

  try {
    // 【核心步骤】前端加密密码
    const encryptedPassword = encryptPassword(loginForm.password, publicKey.value);

    // 构造发送数据,注意发送的是加密后的字符串
    const payload = {
      username: loginForm.username,
      password: encryptedPassword, 
      // 可选:有些方案会带上时间戳或随机盐值防止重放攻击
      // timestamp: Date.now() 
    };

    // 发送登录请求
    const res = await request.post('/auth/login', payload);

    if (res.code === 200) {
      alert('登录成功');
      // 存储 token 等操作
      // localStorage.setItem('token', res.data.token);
    } else {
      alert(res.message || '登录失败');
    }
  } catch (error) {
    console.error('登录异常', error);
    alert('登录失败,请检查网络或联系管理员');
  } finally {
    loading.value = false;
    // 安全起见,加密后立即清空明文密码
    loginForm.password = ''; 
  }
};

onMounted(() => {
  fetchPublicKey();
});
</script>

<style scoped>
/* 简单样式 */
.login-container { max-width: 400px; margin: 50px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; }
.form-item { margin-bottom: 15px; }
input { width: 100%; padding: 8px; box-sizing: border-box; }
button { width: 100%; padding: 10px; background: #42b983; color: white; border: none; cursor: pointer; }
button:disabled { background: #ccc; }
</style>

4. 后端配合要点 (简述)

前端做了加密,后端必须能解密,否则无法验证。

  1. 生成密钥对

    • 后端启动时生成一对 RSA 密钥(或使用固定的密钥对存储在配置中心/数据库中)。
    • 私钥 :严格保存在后端服务器内存或安全存储中,绝不暴露给前端。
    • 公钥:提供给前端接口下载。
  2. 提供公钥接口

    • 接口示例:GET /api/auth/public-key
    • 返回 PEM 格式的公钥字符串。
  3. 登录接口解密

    • 接收前端传来的 encryptedPassword
    • 使用私钥进行解密,得到原始密码 rawPassword
    • 重要 :拿到 rawPassword 后,不要直接跟数据库里的明文比(数据库里存的应该是加盐哈希值,如 BCrypt)。
    • 流程:解密得到明文 -> 使用同样的哈希算法(如BCrypt)计算哈希 -> 与数据库哈希值比对
相关推荐
tangdou3690986552 小时前
图文并茂安装Claude Code 以及配置 Coding Plan 教程
前端·人工智能·后端
arvin_xiaoting2 小时前
OpenClaw学习总结_II_频道系统_4:Slack集成详解
前端·学习·自动化·llm·ai agent·飞书机器人·openclaw
CHU7290352 小时前
让知识传递更顺畅:在线教学课堂APP的功能设计
前端·人工智能·小程序
周淳APP2 小时前
【React Hook全家桶】大致过一遍React Hooks
前端·javascript·react.js·前端框架·react hooks
sheji34162 小时前
【开题答辩全过程】以 基于web的图书借阅系统的设计与实现为例,包含答辩的问题和答案
前端
●VON2 小时前
Flutter组件深度解析:从基础到高级的完整指南
android·javascript·flutter·harmonyos·von
CodeSheep2 小时前
两位大佬相继离世,AI时代我们活得太着急了
前端·后端·程序员
xuankuxiaoyao2 小时前
VUE.JS 实践 第三章
前端·javascript·vue.js