You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular用node-forge RSA加密请求体,ASP.NET Core 6解密返回[object object]问题

RSA-OAEP加密解密异常:Angular(node-forge)加密后ASP.NET Core解密返回[object object]

问题说明

在Angular中使用node-forge实现RSA-OAEP加密请求体,ASP.NET Core 6后端解密时无法获取正确明文,仅输出[object object],尝试通过PEM读取密钥未解决问题。

Angular端加密代码

import { Injectable } from '@angular/core';
import * as Forge from 'node-forge';

@Injectable({
  providedIn: 'root',
})
export class RSA {
  publicKey: string =`-----BEGIN PUBLIC KEY-----
  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArHQ09caWERhxf9deHJr2
  AXwBUQuUdmjuZRRTAvkx+VkytEdycTgt8wNR53jjCCSeyK4EeeU04nzoTW6Sqh77
  gTK3T9rPy6QPjD7IrFNZeLwwDfy5SFe9G2vzbJ1geyMgSdBAMITOXK9cdAnsCC40
  dNfPKly3BCf2SI+6Z3zJXghJZfKa2iucGrpW1Jwnxdwbtf7gzYBwmdu7lCz7o93F
  pc3Wd7vCCsjl+PafasuGBPPRhqwuo4fbNuTM6D0oaXWd6Y9HoQ6BanortLotoCXO
  WPCJxqyAU52V1H4lgxP8bgYPZFGRrrabgbqsvDivohSxj4xd822LleF7VZD9Gtos
  UQIDAQAB
  -----END PUBLIC KEY-----`;

  constructor() {}

  encryptWithPublicKey(valueToEncrypt: string): string {
     const scheme={
    name: 'RSA-OAEP',
    hash:'sha256'
    
  };
    const rsa = Forge.pki.publicKeyFromPem(this.publicKey);
    const encryptedBytes = rsa.encrypt(valueToEncrypt.toString(),'RSA-OAEP');
    return window.btoa(encryptedBytes);
  }
}

ASP.NET Core 6端解密中间件代码

using Microsoft.AspNetCore.Cors;

using System.Security.Cryptography;
using System.Text;

namespace DotNetServer.Middleware
{
    [EnableCors("_myAllowSpecificOrigins")]
   
    public class Middleware
    {
        private readonly RequestDelegate _next;
        static string privateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEArHQ09caWERhxf9deHJr2AXwBUQuUdmjuZRRTAvkx+VkytEdy
cTgt8wNR53jjCCSeyK4EeeU04nzoTW6Sqh77gTK3T9rPy6QPjD7IrFNZeLwwDfy5
SFe9G2vzbJ1geyMgSdBAMITOXK9cdAnsCC40dNfPKly3BCf2SI+6Z3zJXghJZfKa
2iucGrpW1Jwnxdwbtf7gzYBwmdu7lCz7o93Fpc3Wd7vCCsjl+PafasuGBPPRhqwu
o4fbNuTM6D0oaXWd6Y9HoQ6BanortLotoCXOWPCJxqyAU52V1H4lgxP8bgYPZFGR
rrabgbqsvDivohSxj4xd822LleF7VZD9GtosUQIDAQABAoIBAFnrjeHJVl47nJLI
PW407qj/e8BChXroY8WYv2ABh6k4dVPDHU0jufHIfWBwjBCm55RECFl2xgiCkK4v
RZIm7YUEaMjekxLfzKuX4RLZswFdPsFMUWADP7uYoii0NqZ+Pku+pnmmBeQWG+L1
eXkafoeeL4srJNKp86UKLGvhiS3Zz9QgvJKw2nYoe901Jh+nngzhO9MaTGWLgJa0
4aTMQCZ8qdA1gG6gQ9W9UnVEY7m8CzkSyXFXz/JlvZ/WY8Wl7PM9+2ovl4np5S4Z
MaPBJvVm0/W22MsNDMo6fo8/yiGLu72QyY4X8zQVPp5rtPA1tYr9UcEnhi16AHvz
DDUaoHECgYEA6sP2fzqYWisJz+d+deZXmcT2CUCscJJAeXmyH+DZreEJFmF2D+SH
Vx1+dcPSDFjfKgmL3u9l0A4gw4jVz3J64QulZtL/DhNKCj6/NFAjfd2lKx1pcHW3
ZOkiMES1FxWPcj7SVkG/PDSetDRQu3mLUwWytch2fwCEGaSLJ6Q45ucCgYEAvA1o
q29KCrdcfLH0lh5X58MxHHCGNkT6S2gFY44r8MrQy2Cu3zepQIp+EIVzfVeUALgk
7+5gqbkZf+gUKihSIRg0n6CjplTesJQrGfA/IAmPUpSvKSTYUWhxYLgD6JoTNPHc
jZIsQKz3objDZmO6zNaaEDiuDo3AhkufBOYFxAcCgYEApAyz30wu0jNo8+MsN27y
n/1GgEi1NyS78SbdFfGlqx+pnf4U5h4nhPSTPe/Mg9xGdbWeC/b2CmEU/A5Oelvh
Cgl9V1Dx8gAAqRAXxJKLepS7qlkvKOrZcKaIwXoBoVPrnUXQ7X2cCJIspHg6Qgc5
GJbOvsCKLU1LAjA9HUJgkNkCgYEAjunp2A+Vx5seMK3VYZjh2YKf+isR9IBrb484
OTa88hxQnZ92hrF4cVJPCCNDZ8h89Cb9+1HAKHxBgtFPMdK+x+Prajzc4fWx36Rb
NTU95A0f3PSeQbh8pTGoqIZwgf9GBYChyv2BoA1TjJYr+c5lEnMtVpKcxPa5j9Y8
na5qR1UCgYEAiA4bqKD7cJy2GfNokZhxjej8Y9QGf8fKL4rhh3aIl4diQgUfi+1F
12McPmlwsvfnsuIdGkt/eDdp0Phr/smYbEmKniYQBcHmLc97OH99TyNzySMVeZ5R
rWP1WXLkWOeDOzpuZwKrUuXTDvHJfCsEqmlEujUWeGXxOVN/aOFZI2s=
-----END RSA PRIVATE KEY-----";

       public Middleware(RequestDelegate next)
       {
           _next = next;
       }

       public async Task Invoke(HttpContext httpContext)
       {
            if (httpContext.Request.Method == "POST")
            {
                try 
                {
                    HttpRequest request = httpContext.Request;

                    using (StreamReader reader = new StreamReader(request.Body))
                    {
                        string cypherText = await reader.ReadToEndAsync();
                        byte[] bytesCypherText = Convert.FromBase64String(cypherText);

                        RSA rsa = RSA.Create();
                        rsa.ImportFromPem(privateKey);

                        byte[] decryptedBytes = rsa.Decrypt(bytesCypherText,RSAEncryptionPadding.OaepSHA256);
                        string decryptedText = Encoding.UTF8.GetString(decryptedBytes) ;
                    
                        Console.WriteLine(decryptedText);

                        httpContext.Request.Body = new MemoryStream(decryptedBytes);
                        httpContext.Request.ContentLength = decryptedBytes.Length;
                    }

                    await _next(httpContext);
                }
                catch (Exception e )
                {
                    e.ToString();
                    throw;
                }
            }
            else
            {
                await _next(httpContext);
            }
        }
    }
}

问题原因及修复方案

核心原因

[object object]是因为加密时直接对对象调用toString()方法,JavaScript中对象默认toString()返回值就是[object object],而非对象的实际内容。

修复步骤

  1. Angular端修正加密逻辑

    • 先将加密对象序列化为JSON字符串,再传入加密方法
    • 使用node-forge自带的Base64编码工具,避免window.btoa的编码兼容性问题
    • 显式指定OAEP的哈希算法为SHA256,和后端保持一致

    修改后的加密方法:

    encryptWithPublicKey(valueToEncrypt: any): string {
        // 将对象转为JSON字符串
        const jsonContent = JSON.stringify(valueToEncrypt);
        const rsa = Forge.pki.publicKeyFromPem(this.publicKey);
        // 显式指定SHA256哈希算法
        const encrypted = rsa.encrypt(jsonContent, 'RSA-OAEP', {
            md: Forge.md.sha256.create()
        });
        // 使用forge自带的Base64编码
        return Forge.util.encode64(encrypted);
    }
    
  2. ASP.NET Core端验证
    解密后的字符串是JSON格式,可直接反序列化为对象使用,当前后端的解密逻辑无需修改,只需确保前端传入的加密内容是正确的JSON字符串加密结果。

额外注意事项

  • 公私钥对已匹配,无需更换
  • RSA-OAEP加密内容长度有限制(2048位密钥最多加密214字节),若加密大对象,建议先用AES加密对象,再用RSA加密AES密钥
  • 两端统一使用UTF-8编码,当前代码已符合要求

内容的提问来源于stack exchange,提问作者Aneeq Rehman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 15:12:04