Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions weixin-java-pay/REAL_NAME_USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# 微信支付实名验证接口使用说明

## 概述

微信支付实名验证接口允许商户查询用户的实名认证状态,如果用户未实名认证,接口会返回引导用户进行实名认证的URL。

## 官方文档

https://pay.wechatpay.cn/doc/v2/merchant/4011987607

## 接口说明

### 查询用户实名认证信息

- **接口地址**:`https://api.mch.weixin.qq.com/userinfo/realnameauth/query`
- **请求方式**:POST(需要使用商户证书)
- **请求参数**:
- `appid`:公众账号ID(自动填充)
- `mch_id`:商户号(自动填充)
- `openid`:用户在商户appid下的唯一标识
- `nonce_str`:随机字符串(自动生成)
- `sign`:签名(自动生成)

- **返回参数**:
- `return_code`:返回状态码
- `return_msg`:返回信息
- `result_code`:业务结果
- `openid`:用户标识
- `is_certified`:实名认证状态(Y-已实名认证,N-未实名认证)
- `cert_info`:实名认证信息(加密,仅已实名时返回)
- `guide_url`:引导用户进行实名认证的URL(仅未实名时返回)

## 使用示例

### 1. 获取实名验证服务

```java
// 获取WxPayService实例
WxPayService wxPayService = ... // 根据你的配置初始化

// 获取实名验证服务
RealNameService realNameService = wxPayService.getRealNameService();
```

### 2. 查询用户实名认证状态(完整方式)

```java
import com.github.binarywang.wxpay.bean.realname.RealNameRequest;
import com.github.binarywang.wxpay.bean.realname.RealNameResult;
import com.github.binarywang.wxpay.exception.WxPayException;

try {
// 构建请求对象
RealNameRequest request = RealNameRequest.newBuilder()
.openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o") // 用户的openid
.build();

// 调用查询接口
RealNameResult result = realNameService.queryRealName(request);

// 处理返回结果
if ("Y".equals(result.getIsCertified())) {
System.out.println("用户已实名认证");
System.out.println("认证信息:" + result.getCertInfo());
} else {
System.out.println("用户未实名认证");
System.out.println("引导链接:" + result.getGuideUrl());
// 可以将guide_url提供给用户,引导其完成实名认证
}
} catch (WxPayException e) {
System.err.println("查询失败:" + e.getMessage());
}
```

### 3. 查询用户实名认证状态(简化方式)

```java
import com.github.binarywang.wxpay.bean.realname.RealNameResult;
import com.github.binarywang.wxpay.exception.WxPayException;

try {
// 直接传入openid进行查询
RealNameResult result = realNameService.queryRealName("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");

// 处理返回结果
if ("Y".equals(result.getIsCertified())) {
System.out.println("用户已实名认证");
} else {
System.out.println("用户未实名认证,引导链接:" + result.getGuideUrl());
}
} catch (WxPayException e) {
System.err.println("查询失败:" + e.getMessage());
}
```

## 注意事项

1. **证书要求**:本接口需要使用商户证书进行请求,请确保已正确配置商户证书。

2. **OPENID获取**:openid是用户在商户appid下的唯一标识,需要通过微信公众平台或小程序获取。

3. **认证信息**:`cert_info`字段返回的信息是加密的,需要使用相应的解密方法才能获取明文信息。

4. **引导链接**:当用户未实名时,返回的`guide_url`可以用于引导用户完成实名认证,建议在小程序或H5页面中使用。

5. **频率限制**:请注意接口调用频率限制,避免频繁查询同一用户的实名状态。

## 业务场景

- **转账前校验**:在进行企业付款到零钱等操作前,可以先查询用户的实名认证状态
- **风控审核**:作为业务风控的一部分,确认用户已完成实名认证
- **用户引导**:发现用户未实名时,引导用户完成实名认证以使用相关功能

## 错误处理

```java
try {
RealNameResult result = realNameService.queryRealName(openid);
// 处理结果...
} catch (WxPayException e) {
// 处理异常
String errorCode = e.getErrCode();
String errorMsg = e.getErrCodeDes();

// 根据错误码进行相应处理
switch (errorCode) {
case "SYSTEMERROR":
// 系统错误,建议稍后重试
break;
case "PARAM_ERROR":
// 参数错误,检查openid是否正确
break;
default:
// 其他错误
break;
}
}
```

## 相关链接

- [微信支付官方文档](https://pay.wechatpay.cn/doc/v2/merchant/4011987607)
- [WxJava项目主页](https://github.com/binarywang/WxJava)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.github.binarywang.wxpay.bean.realname;

import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;

import java.util.Map;

/**
* <pre>
* 微信支付实名验证请求对象.
* 详见文档:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
@EqualsAndHashCode(callSuper = true)
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method overrides BaseWxPayRequest.canEqual; it is advisable to add an Override annotation.

Copilot uses AI. Check for mistakes.
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class RealNameRequest extends BaseWxPayRequest {
private static final long serialVersionUID = 1L;

/**
* <pre>
* 字段名:用户标识
* 变量名:openid
* 是否必填:是
* 类型:String(128)
* 示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* 描述:用户在商户appid下的唯一标识
* </pre>
*/
@Required
@XStreamAlias("openid")
private String openid;

@Override
protected void checkConstraints() {
//do nothing
}

@Override
protected void storeMap(Map<String, String> map) {
map.put("openid", openid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.github.binarywang.wxpay.bean.realname;

import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.w3c.dom.Document;

import java.io.Serializable;

/**
* <pre>
* 微信支付实名验证返回结果.
* 详见文档:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
@EqualsAndHashCode(callSuper = true)
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method overrides BaseWxPayResult.canEqual; it is advisable to add an Override annotation.

Copilot uses AI. Check for mistakes.
@NoArgsConstructor
@XStreamAlias("xml")
public class RealNameResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;

/**
* <pre>
* 字段名:用户标识
* 变量名:openid
* 是否必填:否
* 类型:String(128)
* 示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* 描述:用户在商户appid下的唯一标识
* </pre>
*/
@XStreamAlias("openid")
private String openid;

/**
* <pre>
* 字段名:实名认证状态
* 变量名:is_certified
* 是否必填:是
* 类型:String(1)
* 示例值:Y
* 描述:Y-已实名认证 N-未实名认证
* </pre>
*/
@XStreamAlias("is_certified")
private String isCertified;

/**
* <pre>
* 字段名:实名认证信息
* 变量名:cert_info
* 是否必填:否
* 类型:String(256)
* 示例值:
* 描述:实名认证的相关信息,如姓名等(加密)
* </pre>
*/
@XStreamAlias("cert_info")
private String certInfo;

/**
* <pre>
* 字段名:引导链接
* 变量名:guide_url
* 是否必填:否
* 类型:String(256)
* 示例值:
* 描述:未实名时,引导用户进行实名认证的URL
* </pre>
*/
@XStreamAlias("guide_url")
private String guideUrl;

/**
* 从XML结构中加载额外的属性
*
* @param d Document
*/
@Override
protected void loadXml(Document d) {
openid = readXmlString(d, "openid");
isCertified = readXmlString(d, "is_certified");
certInfo = readXmlString(d, "cert_info");
guideUrl = readXmlString(d, "guide_url");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.github.binarywang.wxpay.service;

import com.github.binarywang.wxpay.bean.realname.RealNameRequest;
import com.github.binarywang.wxpay.bean.realname.RealNameResult;
import com.github.binarywang.wxpay.exception.WxPayException;

/**
* <pre>
* 微信支付实名验证相关服务类.
* 详见文档:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface RealNameService {
/**
* <pre>
* 获取用户实名认证信息API.
* 用于商户查询用户的实名认证状态,如果用户未实名认证,会返回引导用户实名认证的URL
* 文档详见:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* 接口链接:https://api.mch.weixin.qq.com/userinfo/realnameauth/query
* </pre>
*
* @param request 请求对象
* @return 实名认证查询结果
* @throws WxPayException the wx pay exception
*/
RealNameResult queryRealName(RealNameRequest request) throws WxPayException;

/**
* <pre>
* 获取用户实名认证信息API(简化方法).
* 用于商户查询用户的实名认证状态,如果用户未实名认证,会返回引导用户实名认证的URL
* 文档详见:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* 接口链接:https://api.mch.weixin.qq.com/userinfo/realnameauth/query
* </pre>
*
* @param openid 用户openid
* @return 实名认证查询结果
* @throws WxPayException the wx pay exception
*/
RealNameResult queryRealName(String openid) throws WxPayException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,13 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
*/
PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService();

/**
* 获取实名验证服务类
*
* @return the real name service
*/
RealNameService getRealNameService();

Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在 WxPayService 接口中的 getRealNameService() 方法后存在多余的空行。为了保持代码风格一致性,应该删除第 1716 行的空行,使其与其他服务方法的格式保持一致。

Suggested change

Copilot uses AI. Check for mistakes.
/**
* 获取医保支付服务类
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
@Getter
private final BusinessOperationTransferService businessOperationTransferService = new BusinessOperationTransferServiceImpl(this);

@Getter
private final RealNameService realNameService = new RealNameServiceImpl(this);

Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在 BaseWxPayServiceImpl 中的 realNameService 字段初始化后存在多余的空行。为了保持代码风格一致性,应该删除第 142 行的空行,使其与其他服务字段的格式保持一致。

Suggested change

Copilot uses AI. Check for mistakes.
@Getter
private final MiPayService miPayService = new MiPayServiceImpl(this);

Comment on lines +140 to 145
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method overrides WxPayService.getRealNameService; it is advisable to add an Override annotation.

Suggested change
@Getter
private final RealNameService realNameService = new RealNameServiceImpl(this);
@Getter
private final MiPayService miPayService = new MiPayServiceImpl(this);
private final RealNameService realNameService = new RealNameServiceImpl(this);
@Getter
private final MiPayService miPayService = new MiPayServiceImpl(this);
@Override
public RealNameService getRealNameService() {
return this.realNameService;
}

Copilot uses AI. Check for mistakes.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.binarywang.wxpay.service.impl;

import com.github.binarywang.wxpay.bean.realname.RealNameRequest;
import com.github.binarywang.wxpay.bean.realname.RealNameResult;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.RealNameService;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.RequiredArgsConstructor;

/**
* <pre>
* 微信支付实名验证相关服务实现类.
* 详见文档:https://pay.wechatpay.cn/doc/v2/merchant/4011987607
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@RequiredArgsConstructor
public class RealNameServiceImpl implements RealNameService {
private final WxPayService payService;

@Override
public RealNameResult queryRealName(RealNameRequest request) throws WxPayException {
request.checkAndSign(this.payService.getConfig());
String url = this.payService.getPayBaseUrl() + "/userinfo/realnameauth/query";

String responseContent = this.payService.post(url, request.toXML(), true);
RealNameResult result = BaseWxPayResult.fromXML(responseContent, RealNameResult.class);
result.checkResult(this.payService, request.getSignType(), true);
return result;
}

@Override
public RealNameResult queryRealName(String openid) throws WxPayException {
RealNameRequest request = RealNameRequest.newBuilder()
.openid(openid)
.build();
return this.queryRealName(request);
}
}
Loading