Swish API 付款请求:错误“PA01:参数不正确”

问题描述 投票:0回答:1

我正在尝试使用 Node.js 和 Express 集成 Swish API 以进行支付请求。尽管密切关注文档,我仍然遇到 401 未经授权的错误:

{
  "errorCode": "PA01",
  "errorMessage": "Parameter is not correct.",
  "additionalInformation": null
}

这是我当前的代码:

const express = require('express');
const fs = require('fs');
const crypto = require('crypto');
const https = require('https');
const path = require('path');
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
const forge = require('node-forge');
const { execSync } = require('child_process');

const app = express();
app.use(express.json());

const basePath = '/Users/xx/downloads/mss_test_2.0/Getswish_Test_Certificates/';

const authCertPath = path.join(basePath, 'Swish_Merchant_TestCertificate_1234679304.p12');
const signingCertPath = path.join(basePath, 'Swish_Merchant_TestSigningCertificate_1234679304.p12');
const caCertPath = path.join(basePath, 'Swish_TLS_RootCA.pem');

const passphrase = 'swish'; // Assuming this is the passphrase for both certificates

const getCertAndKeyFromP12 = (p12Path, passphrase) => {
    const p12Content = fs.readFileSync(p12Path, 'binary');
    const p12Asn1 = forge.asn1.fromDer(p12Content);
    const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, passphrase);
    const keyObj = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })[forge.pki.oids.pkcs8ShroudedKeyBag][0];
    const certObj = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag][0];
    const key = forge.pki.privateKeyToPem(keyObj.key);
    const cert = forge.pki.certificateToPem(certObj.cert);
    return { cert, key };
};

const getCertificateSerialNumber = (certPath, passphrase) => {
    const certContent = fs.readFileSync(certPath, 'binary');
    const p12Asn1 = forge.asn1.fromDer(certContent);
    const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, passphrase);
    const certObj = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag][0];
    const cert = forge.pki.certificateToPem(certObj.cert);
    const serialNumber = certObj.cert.serialNumber.toUpperCase();
    console.log(`Extracted Serial Number: ${serialNumber}`);
    return serialNumber;
};

const getHashedPayload = (payload) => {
    return crypto.createHash('sha512').update(payload).digest();
};

const getCertificateSignature = (hash, privateKey) => {
    const sign = crypto.createSign('RSA-SHA512');
    sign.update(hash);
    sign.end();
    return sign.sign(privateKey, 'base64');
};

app.post('/create-payout', (req, res) => {
    const { cert, key: signingPrivateKey } = getCertAndKeyFromP12(signingCertPath, passphrase);

    const payload = {
        amount: parseFloat(req.body.amount,2).toString(),
        currency: 'SEK',
        instructionDate: new Date().toISOString(),
        message: req.body.message,
        payeeAlias: '0728648607',
        payeeSSN: '196702234292',
        payerAlias: '1234679304',
        payerPaymentReference: 'mockedPayerPaymentReference',
        payoutInstructionUUID: '822735C159A944DBB2B3546717BC919F',
        payoutType: 'PAYOUT',
        signingCertificateSerialNumber: getCertificateSerialNumber(signingCertPath, passphrase)
    };

    const payloadString = JSON.stringify(payload);
    const payloadHash = getHashedPayload(payloadString);
    const signature = getCertificateSignature(payloadHash, signingPrivateKey);

    const requestBody = {
        payload,
        signature,
        callbackUrl: 'https://xxxx.ngrok-free.app/swishcallback'
    };
console.log(JSON.stringify(requestBody))
    const requestOptions = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(requestBody),
        agent: new https.Agent({
            pfx: fs.readFileSync(authCertPath),
            passphrase: passphrase,
            ca: fs.readFileSync(caCertPath)
        })
    };

    fetch('https://mss.cpc.getswish.net/swish-cpcapi/api/v1/payouts', requestOptions)
        .then(response => response.json())
        .then(data => res.json(data))
        .catch(error => res.status(500).json({ error: error.message }));
});

app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000');
});




请求正文:

{
  "amount": 100.00,
  "message": "example message"
}

我按照 Swish API 文档使用 Node.js 和 Express 创建付款请求。我确保有效负载的格式正确,并使用所需的加密方法生成签名。我在请求设置中包含了必要的证书和密钥。

我正在寻找可能导致此错误的原因以及解决方法。任何帮助将不胜感激!

Swish API 文档: https://developer.swish.nu/documentation/environments https://developer.swish.nu/api/mss/v1#create-payout-request

node.js express swish
1个回答
0
投票

针对 pA01 问题进行格式化

const express = require('express');
    const fs = require('fs');
    const crypto = require('crypto');
    const https = require('https');
    const path = require('path');
    const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
    const forge = require('node-forge');
    
    const app = express();
    app.use(express.json());
    
    const basePath = '/Users/xx/downloads/mss_test_2.0/Getswish_Test_Certificates/';
    
    const authCertPath = path.join(basePath, 'Swish_Merchant_TestCertificate_1234679304.p12');
    const signingCertPath = path.join(basePath, 'Swish_Merchant_TestSigningCertificate_1234679304.p12');
    const caCertPath = path.join(basePath, 'Swish_TLS_RootCA.pem');
    
    const passphrase = 'swish'; // Assuming this is the passphrase for both certificates
    
    const getCertAndKeyFromP12 = (p12Path, passphrase) => {
        const p12Content = fs.readFileSync(p12Path, 'binary');
        const p12Asn1 = forge.asn1.fromDer(p12Content);
        const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, passphrase);
        const keyObj = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })[forge.pki.oids.pkcs8ShroudedKeyBag][0];
        const certObj = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag][0];
        const key = forge.pki.privateKeyToPem(keyObj.key);
        const cert = forge.pki.certificateToPem(certObj.cert);
        return { cert, key };
    };
    
    const getCertificateSerialNumber = (certPath, passphrase) => {
        const certContent = fs.readFileSync(certPath, 'binary');
        const p12Asn1 = forge.asn1.fromDer(certContent);
        const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, passphrase);
        const certObj = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag][0];
        const serialNumber = certObj.cert.serialNumber.toUpperCase();
        console.log(`Extracted Serial Number: ${serialNumber}`);
        return serialNumber;
    };
    
    const getHashedPayload = (payload) => {
        return crypto.createHash('sha512').update(payload).digest();
    };
    
    const getCertificateSignature = (hash, privateKey) => {
        const sign = crypto.createSign('RSA-SHA512');
        sign.update(hash);
        sign.end();
        return sign.sign(privateKey, 'base64');
    };
    
    app.post('/create-payout', (req, res) => {
        const { cert, key: signingPrivateKey } = getCertAndKeyFromP12(signingCertPath, passphrase);
    
        // Create the payload
        const payload = {
            amount: parseFloat(req.body.amount).toFixed(2), // Ensure amount is formatted correctly
            currency: 'SEK',
            instructionDate: new Date().toISOString().replace(/\.\d+Z$/, 'Z'), // Ensure correct format
            payeeAlias: '0728648607',
            payeeSSN: '196702234292',
            payerAlias: '1234679304',
            payerPaymentReference: 'mockedPayerPaymentReference',
            payoutInstructionUUID: '822735C159A944DBB2B3546717BC919F',
            payoutType: 'PAYOUT',
            signingCertificateSerialNumber: getCertificateSerialNumber(signingCertPath, passphrase)
        };
    
        // Add message field if provided and valid
        if (req.body.message && req.body.message.length <= 50) {
            payload.message = req.body.message;
        }
    
        const payloadString = JSON.stringify(payload);
        const payloadHash = getHashedPayload(payloadString);
        const signature = getCertificateSignature(payloadHash, signingPrivateKey);
    
        const requestBody = {
            payload,
            signature,
            callbackUrl: 'https://xxxx.ngrok-free.app/swishcallback'
        };
    
        console.log('Request Body:', JSON.stringify(requestBody));
    
        const requestOptions = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(requestBody),
            agent: new https.Agent({
                pfx: fs.readFileSync(authCertPath),
                passphrase: passphrase,
                ca: fs.readFileSync(caCertPath)
            })
        };
    
        fetch('https://mss.cpc.getswish.net/swish-cpcapi/api/v1/payouts', requestOptions)
            .then(response => {
                if (!response.ok) {
                    // Handle non-2xx responses
                    console.log('Error Response:', response.statusText);
                    return response.json().then(errorData => {
                        throw new Error(`Swish API error: ${errorData.errorCode} - ${errorData.errorMessage}`);
                    });
                }
                return response.json();
            })
            .then(data => {
                console.log('API Response:', data);
                res.json(data);
            })
            .catch(error => {
                console.error('Request Error:', error.message);
                res.status(500).json({ error: error.message });
            });
    });
    
    app.listen(3000, () => {
        console.log('Server is running on http://localhost:3000');
    });
© www.soinside.com 2019 - 2024. All rights reserved.