# API 认证

> 🔐 **重要提示**：请严格按照本文档说明进行 API 认证与签名，确保安全通信。


## 必要头部参数

### 请求头参数

| 参数名  | 含义描述 | 类型  | 必填  |
|  --- | --- | --- | --- |
| `signature` | 请求签名 | String[1,500] | ✅ |
| `type` | 签名类型，固定传 `RSA256` | String[1,10] | ✅ |
| `version` | 版本号，固定传 `v1.2` | String[1,10] | ✅ |


### 响应头参数

| 参数名  | 含义描述 | 类型  | 必填  |
|  --- | --- | --- | --- |
| `signature` | 响应签名 | String[1,500] | ✅ |
| `type` | 签名类型，固定传 `RSA256` | String[1,10] | ✅ |
| `version` | 版本号，固定传 `v1.2` | String[1,10] | ✅ |


## 示例

### 请求体

```json
{
    "merchant_id": "YOUR_MERCHANT_ID",
    "payment_type": "PURCHASE",
    "authorisation_type": "FINAL_AUTH",
    "capture_method": "AUTOMATIC",
    "trans_id": "t202311081113",
    "timestamp": 1700805506000,
    "amount": 445,
    "currency": "EUR",
    "notify_url": "https://www.baidu.com/notifyUrl",
    "return_url": "https://www.baidu.com/returnUrl",
    "payment": {
        "payment_method": "BankCard",
        "store_payment_method": false,
        "token_usage": "CARD_ON_FILE",
        "shopper_reference": "user1234567890",
        "encrypted_card_no": "string",
        "encrypted_exp_year": "string",
        "encrypted_exp_month": "string",
        "encrypted_cvv": "string"
    }
}
```

### 响应体

```json
{
  "ret_code": "000000",
  "ret_msg": "Success",
  "data": {
    "timestamp": 1700805506000,
    "merchant_id": "YOUR_MERCHANT_ID",
    "trans_id": "t202311081113",
    "order_id": "GW20598371023658327",
    "status": "AUTHORIZED",
    "authorisation_type": "FINAL_AUTH",
    "capture_method": "AUTOMATIC",
    "amount": 445,
    "currency": "EUR",
    "payment": {
      "payment_method": "BANKCARD"
    },
    "card_info": {
      "bin": "424242",
      "last4": "4242",
      "card_brand": "VISA"
    },
    "balances": {
      "authed_amount": 445,
      "captured_amount": 0,
      "able_to_capture_amount": 445,
      "voided_amount": 0,
      "able_to_void_amount": 445,
      "refunded_amount": 0,
      "able_to_refund_amount": 0
    }
  }
}
```

## 计算签名

### 添加依赖

在您的 Java 代码中引入依赖：

```xml
<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.15</version>
</dependency>
```

### 生成签名

从请求参数中依次组合 `merchant_id`、`timestamp` 和请求体 `requestBody` 内容，拼接为字符串后，使用您的私钥进行 SHA256withRSA 算法生成签名：

```java
private static final String FORMAT = "merchantId=%s&timestamp=%s&requestBody=%s";

String content = String.format(FORMAT, merchantId, timestamp, requestBody);
Signature signature = Signature.getInstance("SHA256withRSA");
byte[] privateKeys = Base64Utils.decodeFromString(privateKey);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeys);
PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);
signature.initSign(priKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
byte[] signed = signature.sign();
String result = Base64Utils.encodeToString(signed);
String sign = URLEncoder.encode(result);
log.info("生成签名：{}", sign);
```

### 设置请求头

1. 将签名设置到请求头 `signature` 中，并确保请求体和签名参数 `requestBody` 完全一致
2. 设置请求头 `type` 为 `RSA256`，表示使用的签名方式
3. 设置请求头 `version` 为 `v1.2`，表示使用的 API 版本


### 请求示例

```bash
curl 'https://openapi-sandbox.paykka.com/payments' -X POST \
 -H 'Content-Type: application/json'\
 -H 'type: RSA256'\
 -H 'version: v1.2'\
 -H 'signature: SOjw%2FOwcMM2jCB7xxxxxxxxxOtFyY%2BvWE%2FFXefazBA%3D%3D'\
 -d '{"merchant_id": "YOUR_MERCHANT_ID"}'
```

## 验证签名

> ⚠️ **注意**: 验证签名时使用的公钥是 PayKKa 公钥


```java
String content = String.format(FORMAT, merchantId, timestamp, requestBody);
Signature signature = Signature.getInstance("SHA256withRSA");
byte[] publicKeys = Base64Utils.decodeFromString(publicKey);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeys);
PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);
signature.initVerify(pubKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
String channelSignature = URLDecoder.decode("signatureDataFromPayKKa", StandardCharsets.UTF_8);
boolean verified = signature.verify(Base64Utils.decodeFromString(channelSignature));
```