Python+Vue非对称加解密实践
引言
在Web应用中,数据安全是至关重要的考量因素。非对称加密算法因其安全性高、使用灵活,被广泛应用于数据传输加密、数字签名等场景。本文将详细介绍如何在Python后端和Vue前端中实现非对称加解密功能。
RSA加密原理简介
RSA是一种非对称加密算法,它使用一对密钥:公钥和私钥。公钥用于加密数据,私钥用于解密数据。这种特性使得RSA非常适合以下场景:
-
敏感数据加密传输
-
数字签名和身份验证
-
安全密钥交换
环境准备
后端依赖安装
pip install cryptography
cryptography是Python中一个功能强大且易用的加密库,提供了各种加密算法的实现。
前端依赖安装
pnpm add jsencrypt
# 或使用npm
npm install jsencrypt
# 或使用yarn
yarn add jsencrypt
jsencrypt是一个纯JavaScript实现的RSA加密库,专门为Web应用设计。
后端加解密核心代码
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
import base64
import os
PRIVATE_KEY_FILE = "private_key.pem"
PUBLIC_KEY_FILE = "public_key.pem"
def initialize_keys():
"""初始化密钥:加载现有密钥或生成新密钥对"""
global private_key, public_key
if os.path.exists(PRIVATE_KEY_FILE) and os.path.exists(PUBLIC_KEY_FILE):
# 加载已存在的密钥
with open(PRIVATE_KEY_FILE, "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
with open(PUBLIC_KEY_FILE, "rb") as f:
public_key = serialization.load_pem_public_key(f.read())
else:
# 生成新的密钥对并保存
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
# 保存私钥(生产环境应加密存储)
with open(PRIVATE_KEY_FILE, "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
))
# 保存公钥
with open(PUBLIC_KEY_FILE, "wb") as f:
f.write(public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
))
def get_public_key_pem() -> str:
"""获取PEM格式的公钥,供前端使用"""
pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
return pem.decode()
def get_private_key_pem() -> str:
"""获取PEM格式的私钥,供前端使用"""
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
return pem.decode()
def encrypt_data_with_public_key(data: str, public_key_pem: str) -> str:
"""使用公钥加密数据(模拟前端加密过程)"""
public_key = serialization.load_pem_public_key(public_key_pem.encode())
encrypted_data = public_key.encrypt(
data.encode(),
padding.PKCS1v15()
)
return base64.b64encode(encrypted_data).decode()
def decrypt_data(encrypted_data: str) -> str:
"""使用私钥解密数据(后端解密)"""
encrypted_bytes = base64.b64decode(encrypted_data.encode())
decrypted_data = private_key.decrypt(
encrypted_bytes,
padding.PKCS1v15()
)
return decrypted_data.decode()
# 生成公钥私钥
initialize_keys()
详解:
1、initialize_keys()
实现了密钥的智能管理:
-
首先检查是否已存在密钥文件
-
如果存在,直接加载现有密钥
-
如果不存在,生成新的RSA密钥对并保存到文件
安全提醒:生产环境中,私钥应该加密存储,并使用安全的密码保护。
2、加密过程说明:
encrypt_data_with_public_key():
-
将PEM格式的公钥字符串加载为公钥对象
-
使用PKCS1v15填充方案对数据进行加密
-
将加密后的二进制数据转换为Base64字符串,便于网络传输
3、解密过程说明:
decrypt_data():
-
将Base64编码的加密数据解码为二进制
-
使用私钥和相同的填充方案进行解密
-
将解密后的二进制数据转换为字符串
4、后端接口获取公私秘钥:
用于前端请求数据前加密,回显后解密,这里以fastapi为例:
...
@app.get("/get_public_key", summary="获取公钥", tags=["公私秘钥"])
async def get_public_key(auth: Auth = Depends(AllUserAuth())):
if not auth:
return ErrorResponse("请先登录")
return SuccessResponse(data=get_public_key_pem())
@app.get("/get_private_key", summary="获取私钥", tags=["公私秘钥"])
async def get_private_key(auth: Auth = Depends(AllUserAuth())):
if not auth:
return ErrorResponse("请先登录")
return SuccessResponse(data=get_private_key_pem())
...
接口设计要点:
-
公钥私钥接口需要身份验证后才能获取
-
返回PEM格式的公钥字符串,便于前端直接使用
前端加解密核心代码
<script setup lang="tsx">
...
import { addObjApi, getObjApi, getObjListApi, delObjListApi, putObjApi, getPublicKeyApi, getPrivateKeyApi } from './api'
...
// 导入加密工具
import { JSEncrypt } from 'jsencrypt'
// 加密实例
const encryptor = ref(new JSEncrypt())
const publicKey = ref('')
const privateKey = ref('')
// 获取公钥
const fetchPublicKey = async () => {
try {
const res = await getPublicKeyApi()
if (res.data) {
publicKey.value = res.data
encryptor.value.setPublicKey(publicKey.value)
}
} catch (error) {
console.error('获取公钥失败:', error)
}
}
// 加密数据
const encryptData = (data: string): string => {
if (!publicKey.value) {
ElMessage.warning('加密公钥未就绪')
return data
}
try {
const encrypted = encryptor.value.encrypt(data)
return encrypted || data
} catch (error) {
console.error('加密失败:', error)
ElMessage.error('数据加密失败')
return data
}
}
// 获取私钥
const fetchPrivateKey = async () => {
try {
const res = await getPrivateKeyApi()
if (res.data) {
privateKey.value = res.data
encryptor.value.setPrivateKey(privateKey.value)
}
} catch (error) {
console.error('获取私钥失败:', error)
}
}
// 解密数据
const decryptData = (encryptedData: string): string => {
if (!privateKey.value) {
ElMessage.warning('解密私钥未就绪')
return encryptedData
}
try {
const decrypted = encryptor.value.decrypt(encryptedData)
return decrypted || encryptedData
} catch (error) {
console.error('解密失败:', error)
ElMessage.error('数据解密失败')
return encryptedData
}
}
const { tableRegister, tableState, tableMethods } = useTable({
fetchDataApi: async () => {
const { pageSize, currentPage } = tableState
const res = await getObjListApi({
page: unref(currentPage),
limit: unref(pageSize)
})
// 对加密的数据进行解密,回显到前端展示
const decryptedList = (res.data || []).map(item => {
if (item.is_encrypt && item.var_value) {
return {
...item,
var_value: decryptData(item.var_value)
}
}
return item
})
return {
list: decryptedList,
total: res.count || 0
}
},
fetchDelApi: async (value) => {
const res = await delObjListApi(value)
return res.code === 200
}
})
...
// 组件挂载时获取公私钥
onMounted(() => {
fetchPublicKey()
fetchPrivateKey()
})
</script>
详解:
1、数据加密(encryptData):
加密注意事项:
-
检查公钥是否已准备就绪
-
实现降级策略,加密失败时返回原始数据
-
提供用户友好的错误提示
2、数据解密(decryptData):
解密功能特点:
-
同样实现降级处理,解密失败返回加密数据
-
适用于处理从后端获取的加密数据
总结
本文详细介绍了在Python+Vue项目中实现非对称加解密的完整方案。通过前后端分离的方式实现了:
-
后端的密钥生成、管理和加解密功能
-
前端的密钥获取、数据加密和解密功能
更多推荐

所有评论(0)