30.登录用户名密码 RSA 加密传输-后端为java

30.登录时用户名密码 RSA 加密传输-后端为java

使用 Spring Initializr 创建项目,实现前端登录时用户名密码的 RSA 加密传输


1. 创建后端项目(Spring Boot)

(1)用 Spring Initializr 生成项目

  • 访问 https://start.spring.io/
  • 填写:
    • Project: Maven
    • Language: Java
    • Spring Boot:
    • Group : com.example
    • Artifact : secure-login
    • Dependencies : 选 Spring Web(提供 API 支持)
  • 点击 Generate 下载项目,解压后用 IDE(如 IntelliJ IDEA)打开。


(2)后端核心代码

① 生成 RSA 密钥对

src/main/java/com/example/securelogin/ 下创建 RsaUtil.java

java 复制代码
package com.example.securelogin;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaUtil {

    // 生成 RSA 密钥对(2048位)
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        return generator.generateKeyPair();
    }

    // 公钥加密
    public static String encrypt(String data, String publicKeyStr) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    // 私钥解密
    public static String decrypt(String encryptedData, String privateKeyStr) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}
② 创建 Controller 提供公钥和接收加密数据

src/main/java/com/example/securelogin/ 下创建 AuthController.java

java 复制代码
package com.example.securelogin;

import org.springframework.web.bind.annotation.*;

import java.security.KeyPair;
import java.util.Base64;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    private String publicKey;
    private String privateKey;

    // 项目启动时生成密钥对
    public AuthController() throws Exception {
        KeyPair keyPair = RsaUtil.generateKeyPair();
        this.publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        this.privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
    }

    // 1. 前端获取公钥
    @GetMapping("/public-key")
    public String getPublicKey() {
        return publicKey;
    }

    // 2. 前端提交加密后的用户名密码
    @PostMapping("/login")
    public String login(@RequestBody LoginRequest request) throws Exception {
        String decryptedData = RsaUtil.decrypt(request.getEncryptedData(), privateKey);
        System.out.println("解密后的数据: " + decryptedData); // 实际项目中验证用户名密码
        return "登录成功!";
    }

    // 前端传输的数据格式
    static class LoginRequest {
        private String encryptedData; // 加密后的数据(Base64)

        public String getEncryptedData() {
            return encryptedData;
        }

        public void setEncryptedData(String encryptedData) {
            this.encryptedData = encryptedData;
        }
    }
}

2. 创建前端项目(HTML + JavaScript)

(1)HTML 页面

src/main/resources/static/ 下创建 index.html

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>加密登录</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js"></script>
</head>
<body>
<h1>加密登录示例</h1>
<form id="loginForm">
    <div>
        <label>用户名:</label>
        <input type="text" id="username" required>
    </div>
    <div>
        <label>密码:</label>
        <input type="password" id="password" required>
    </div>
    <button type="button" onclick="login()">登录</button>
</form>

<script src="login.js"></script>
</body>
</html>

(2)JavaScript 加密逻辑

src/main/resources/static/ 下创建 login.js

javascript 复制代码
let publicKey = null;

// 1. 获取后端公钥
async function fetchPublicKey() {
    const response = await fetch('http://localhost:8080/api/auth/public-key');
    publicKey = await response.text();
    console.log("公钥:", publicKey);
}

// 2. 使用 RSA 公钥加密数据
function encryptData(data) {
    const encrypt = new JSEncrypt();
    encrypt.setPublicKey(publicKey);
    return encrypt.encrypt(data);
}

// 3. 提交登录请求
async function login() {
    await fetchPublicKey(); // 先获取公钥

    const username = document.getElementById('username').value;
    const password = document.getElementById('password').value;
    const rawData = `username=${username}&password=${password}`;

    // 加密数据
    const encryptedData = encryptData(rawData);

    // 发送到后端
    const response = await fetch('http://localhost:8080/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ encryptedData: encryptedData })
    });

    const result = await response.text();
    alert(result);
}

// 页面加载时自动获取公钥
window.onload = fetchPublicKey;

3. 测试流程

  1. 启动后端 :运行 SecureLoginApplication 主类(项目启动时会自动生成 RSA 密钥对)。

  2. 打开前端页面 :访问 http://localhost:8080/index.html

  3. 输入用户名密码 (如 admin/123456),点击登录。

    查看网络请求情况


  4. 查看后端控制台 :输出解密后的数据(如 username=admin&password=123456)。


4. 关键点总结

  1. 后端做什么?

    • 生成 RSA 密钥对(启动时生成,无需手动管理)。
    • 提供公钥 API(/api/auth/public-key)。
    • 解密前端传来的加密数据(/api/auth/login)。
  2. 前端做什么?

    • 获取后端公钥。
    • 用公钥加密用户名密码(使用 jsencrypt 库)。
    • 提交加密数据到后端。
  3. 安全建议

    • 必须启用 HTTPS:防止公钥在传输中被窃取。
    • 密钥轮换:定期更换密钥对(可扩展为动态获取公钥)。

5. 最终效果

  • 前端:用户输入用户名密码 → 加密后发送。
  • 后端:解密数据 → 验证用户 → 返回结果。
  • 传输过程:即使被拦截,攻击者也无法直接获取原始密码。

相关推荐
老王熬夜敲代码2 小时前
C++的decltype
开发语言·c++·笔记
益达3212 小时前
IDEA 整合 Git 版本控制:提交、分支管理与冲突解决实操
java·intellij-idea
lxp1997412 小时前
PHP框架自带队列--更新中
开发语言·php
MoonBit月兔2 小时前
海外开发者实践分享:用 MoonBit 开发 SQLC 插件(其三)
java·开发语言·数据库·redis·rust·编程·moonbit
问道飞鱼2 小时前
【Rust编程知识】在 Windows 下搭建完整的 Rust 开发环境
开发语言·windows·后端·rust·开发环境
天呐草莓2 小时前
企业微信运维手册
java·运维·网络·python·微信小程序·企业微信·微信开放平台
jllllyuz2 小时前
C# 面向对象图书管理系统
android·开发语言·c#
小兔崽子去哪了2 小时前
Java 登录专题
java·spring boot·后端
毕设源码-邱学长2 小时前
【开题答辩全过程】以 高校跨校选课系统为例,包含答辩的问题和答案
java·eclipse