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

NodeJS/NestJS带WS-Security的SOAP监听器实现及原始请求获取咨询

解决方案:在NestJS中获取原始SOAP请求并实现WS-Security验证

一、获取原始SOAP请求报文

要处理WS-Security验证,核心是拿到完整的原始SOAP请求内容,你可以通过以下两种方式实现:

1. 利用soap库的request事件拦截

soap库的服务端对象提供了request事件,触发时会直接传入原始HTTP请求对象、响应对象和完整的SOAP XML报文,这是最直接的方式:

import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { Service } from "./serv/serv.service";
import * as soap from 'soap';
import * as http from 'http';
import { DOMParser } from '@xmldom/xmldom';

@Injectable()
export class AppService implements OnApplicationBootstrap {
    constructor(private readonly serv: Service) {}

    onApplicationBootstrap() {
        const server = http.createServer((req, res) => {});
 
        server.listen(3000, () => {
            console.log('listening on port 3000');
        });

        const soapServer = soap.listen(server, '/soap', this.serv.process(), this.serv.getWsdl(), (err) => {
            if (err) {
                console.error('error binding serv WSDL:', err);
            } else {
                console.log('service is running');
            }
        });

        // 拦截SOAP请求,获取原始报文并做WS-Security验证
        soapServer.on('request', (req, res, rawSoapXml) => {
            const isValid = this.validateWsSecurity(rawSoapXml);
            if (!isValid) {
                // 返回SOAP标准错误响应
                res.writeHead(401, {'Content-Type': 'text/xml'});
                res.end(`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
                    <soapenv:Body>
                        <soapenv:Fault>
                            <faultcode>soapenv:Client</faultcode>
                            <faultstring>Invalid WS-Security credentials</faultstring>
                        </soapenv:Fault>
                    </soapenv:Body>
                </soapenv:Envelope>`);
                // 返回false终止soap库后续处理
                return false;
            }
        });
    }

    // 自定义WS-Security验证逻辑
    private validateWsSecurity(rawXml: string): boolean {
        const parser = new DOMParser();
        const doc = parser.parseFromString(rawXml, 'text/xml');
        const wsseNs = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';

        // 提取WS-Security头中的用户名令牌
        const usernameNode = doc.getElementsByTagNameNS(wsseNs, 'Username')[0];
        const passwordNode = doc.getElementsByTagNameNS(wsseNs, 'Password')[0];

        if (!usernameNode || !passwordNode) {
            return false;
        }

        // 替换为你的实际用户验证逻辑(比如查询数据库)
        const validUsername = 'admin';
        const validPassword = 'secure123';
        return usernameNode.textContent === validUsername && passwordNode.textContent === validPassword;
    }
}

2. 在HTTP服务器层面缓存原始请求体

如果需要更底层的控制,可以在创建HTTP服务器时手动收集原始请求体,挂载到请求对象上供后续使用:

const server = http.createServer((req, res) => {
    let rawBody = '';
    req.on('data', chunk => rawBody += chunk.toString());
    req.on('end', () => {
        // 将原始报文挂载到req对象
        (req as any).rawSoapBody = rawBody;
    });
});

之后可以在soapServer的任意钩子(比如authenticate)中通过req.rawSoapBody获取原始内容。

二、扩展WS-Security验证能力

如果需要处理数字签名、时间戳等复杂WS-Security规则,可以:

  • 使用crypto模块解析证书、验证签名值;
  • 针对时间戳(Timestamp元素)检查请求的有效期;
  • 参考OASIS WS-Security规范实现完整的校验逻辑。

三、替代方案:使用支持服务端WS-Security的库

如果不想从零实现,可以尝试strong-soap(原IBM维护的SOAP库),它对服务端WS-Security的支持更完善,内置了用户名令牌、签名验证等常用功能,无需手动解析原始报文。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:23:15