21-检查支付密码接口.md 20 KB

Web端检查支付密码接口文档

模块概述

本模块提供商户用户支付密码检查功能,支持检查用户是否设置了支付密码,以及可选的密码验证功能。


接口信息

检查是否设置支付密码

接口详情

  • 接口名称: 检查是否设置支付密码
  • 接口路径: GET /merchantUser/checkPayPassword
  • 请求方式: GET
  • 接口描述: 检查指定商户用户是否设置了支付密码,并可选择验证密码是否正确
  • 登录验证: ❌ 不需要(公开接口)

请求参数

参数名 类型 必填 说明 示例值
storeUserId String 用户ID "114"
password String 支付密码(如果提供则验证密码是否正确) "123456"

参数说明

  • storeUserId: 商户用户的唯一标识ID
  • password:
    • 如果不提供,只检查用户是否设置了支付密码
    • 如果提供,除了检查是否设置,还会验证密码是否正确

请求示例

示例1: 只检查是否设置支付密码

GET /merchantUser/checkPayPassword?storeUserId=114
curl "http://localhost:8080/merchantUser/checkPayPassword?storeUserId=114"

示例2: 检查并验证支付密码

GET /merchantUser/checkPayPassword?storeUserId=114&password=123456
curl "http://localhost:8080/merchantUser/checkPayPassword?storeUserId=114&password=123456"

响应参数

成功响应(通用格式)

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "...",
        "data": "true/false"
    },
    "msg": "操作成功"
}

响应字段说明

字段名 类型 说明
code Integer HTTP状态码
success Boolean 是否成功
data Map 详细结果数据
data.code Integer 业务状态码(固定为200)
data.message String 结果描述信息
data.data String 验证结果("true"或"false")
msg String 提示信息

data.data 字段值说明

  • "true": 用户已设置支付密码(且密码验证通过,如果提供了password参数)
  • "false": 用户未设置支付密码或密码验证失败

响应示例

场景1: 用户已设置支付密码(不验证密码)

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    },
    "msg": "操作成功"
}

场景2: 用户未设置支付密码

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户未设置支付密码",
        "data": "false"
    },
    "msg": "操作成功"
}

场景3: 用户不存在

请求:

GET /merchantUser/checkPayPassword?storeUserId=999999

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "未查询到用户",
        "data": "false"
    },
    "msg": "操作成功"
}

场景4: 密码验证成功

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=123456

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    },
    "msg": "操作成功"
}

场景5: 密码验证失败

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=wrong_password

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "密码错误",
        "data": "false"
    },
    "msg": "操作成功"
}

场景6: 系统异常

响应:

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败:{异常信息}"
}

业务逻辑说明

处理流程

┌─────────────────────────────────────────────┐
│  1. 接收请求参数                              │
│  - storeUserId (必填)                        │
│  - password (可选)                           │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 根据用户ID查询用户信息                    │
│  storeUserMapper.selectById(storeUserId)     │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 检查用户是否存在                          │
│  IF storeUser == null                        │
│    RETURN "未查询到用户", data="false"       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 检查是否设置了支付密码                    │
│  IF payPassword == null                      │
│    RETURN "用户未设置支付密码", data="false" │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  5. 如果提供了password参数,验证密码          │
│  IF password != null                         │
│    IF password != payPassword                │
│      RETURN "密码错误", data="false"         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  6. 验证通过                                  │
│  RETURN "用户已设置支付密码", data="true"    │
└─────────────────────────────────────────────┘

验证逻辑详解

步骤1: 用户存在性检查

StoreUser storeUser = storeUserMapper.selectById(storeUserId);
if (storeUser == null) {
    // 用户不存在
    return {"message": "未查询到用户", "data": "false"};
}

步骤2: 支付密码设置检查

if (storeUser.getPayPassword() == null) {
    // 用户未设置支付密码
    return {"message": "用户未设置支付密码", "data": "false"};
}

步骤3: 密码验证(可选)

if (password != null) {
    if (!password.equals(storeUser.getPayPassword())) {
        // 密码错误
        return {"message": "密码错误", "data": "false"};
    }
}
// 验证通过
return {"message": "用户已设置支付密码", "data": "true"};

数据库查询

涉及的表

store_user(商户用户表)

查询SQL:

SELECT * FROM store_user WHERE id = ?

使用字段:

  • id: 用户ID
  • pay_password: 支付密码

业务场景

场景1: 支付前检查

背景: 用户发起支付操作前,先检查是否设置了支付密码

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

响应处理:

if (response.data.data === "true") {
    // 已设置支付密码,弹出密码输入框
    showPasswordInput();
} else {
    // 未设置支付密码,引导用户设置
    showSetPasswordTip();
}

场景2: 提现前验证

背景: 用户申请提现时,验证支付密码是否正确

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=123456

响应处理:

if (response.data.data === "true") {
    // 密码验证通过,允许提现
    proceedWithdrawal();
} else {
    // 密码验证失败,提示错误
    showError(response.data.message);
}

场景3: 修改支付密码前验证

背景: 用户修改支付密码前,验证旧密码是否正确

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=old_password

响应处理:

if (response.data.data === "true") {
    // 旧密码正确,允许修改
    showChangePasswordForm();
} else if (response.data.message === "密码错误") {
    // 旧密码错误
    showError("原密码错误,请重新输入");
} else {
    // 其他错误
    showError(response.data.message);
}

场景4: 忘记密码判断

背景: 用户点击"忘记密码",判断是否已设置过密码

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

响应处理:

if (response.data.data === "false" && 
    response.data.message === "用户未设置支付密码") {
    // 从未设置过密码,引导设置
    showSetPasswordPage();
} else {
    // 已设置密码,进入重置流程
    showResetPasswordPage();
}

前端集成示例

Vue.js 示例

// API调用方法
async checkPayPassword(userId, password = null) {
    try {
        const params = { storeUserId: userId };
        if (password) {
            params.password = password;
        }
        
        const response = await axios.get('/merchantUser/checkPayPassword', {
            params: params
        });
        
        if (response.data.success) {
            const result = response.data.data;
            return {
                hasPassword: result.data === "true",
                message: result.message
            };
        }
        
        return { hasPassword: false, message: "查询失败" };
    } catch (error) {
        console.error("检查支付密码失败:", error);
        return { hasPassword: false, message: "网络错误" };
    }
}

// 使用示例1: 检查是否设置支付密码
async function checkIfPasswordSet() {
    const result = await checkPayPassword("114");
    if (result.hasPassword) {
        console.log("用户已设置支付密码");
    } else {
        console.log("用户未设置支付密码:", result.message);
    }
}

// 使用示例2: 验证支付密码
async function verifyPayPassword(password) {
    const result = await checkPayPassword("114", password);
    if (result.hasPassword) {
        console.log("密码验证成功");
        return true;
    } else {
        console.log("密码验证失败:", result.message);
        return false;
    }
}

React 示例

import { useState } from 'react';
import axios from 'axios';

function PaymentComponent() {
    const [hasPassword, setHasPassword] = useState(false);
    const [message, setMessage] = useState('');
    
    // 检查支付密码
    const checkPayPassword = async (userId, password = null) => {
        try {
            const params = { storeUserId: userId };
            if (password) params.password = password;
            
            const response = await axios.get('/merchantUser/checkPayPassword', {
                params
            });
            
            if (response.data.success) {
                const result = response.data.data;
                setHasPassword(result.data === "true");
                setMessage(result.message);
                return result.data === "true";
            }
        } catch (error) {
            console.error('检查失败:', error);
            setMessage('查询失败');
        }
        return false;
    };
    
    return (
        <div>
            <button onClick={() => checkPayPassword("114")}>
                检查是否设置密码
            </button>
            <p>{message}</p>
        </div>
    );
}

安全考虑

1. 密码安全

⚠️ 重要安全建议:

  • 密码应该在数据库中加密存储(MD5、SHA256或BCrypt)
  • 传输密码时应使用HTTPS协议
  • 不要在日志中记录明文密码
  • 考虑添加密码错误次数限制,防止暴力破解

2. 敏感信息保护

当前实现的安全措施:

  • ✅ 日志中不记录明文密码(只记录是否提供了密码)
  • ⚠️ 建议:密码应该加密存储
  • ⚠️ 建议:添加密码错误次数限制

3. 参数验证

  • ✅ 必填参数:storeUserId
  • ✅ 可选参数:password
  • ⚠️ 建议:添加参数格式验证(如用户ID格式、密码长度等)

4. 防暴力破解

建议实现:

// 伪代码示例
if (password != null) {
    // 检查密码错误次数
    int errorCount = getPasswordErrorCount(storeUserId);
    if (errorCount >= 5) {
        return R.fail("密码错误次数过多,请稍后再试");
    }
    
    // 验证密码
    if (!password.equals(storeUser.getPayPassword())) {
        // 记录错误次数
        incrementPasswordErrorCount(storeUserId);
        return R.fail("密码错误");
    }
    
    // 成功后清除错误次数
    clearPasswordErrorCount(storeUserId);
}

日志记录

日志级别

接口记录了详细的日志信息:

// INFO级别 - 请求日志
log.info("MerchantUserController.checkPayPassword?storeUserId={}, hasPassword={}", 
        storeUserId, password != null);

// INFO级别 - 业务开始
log.info("MerchantUserServiceImpl.checkPayPassword - 检查支付密码: storeUserId={}, hasPassword={}", 
        storeUserId, password != null);

// WARN级别 - 异常情况
log.warn("MerchantUserServiceImpl.checkPayPassword - 用户不存在: storeUserId={}", storeUserId);
log.warn("MerchantUserServiceImpl.checkPayPassword - 密码错误: storeUserId={}", storeUserId);

// INFO级别 - 业务完成
log.info("MerchantUserServiceImpl.checkPayPassword - 检查完成: storeUserId={}, result=true", storeUserId);

// ERROR级别 - 异常日志
log.error("MerchantUserController.checkPayPassword ERROR: {}", e.getMessage(), e);

日志安全

重要:

  • ✅ 不记录明文密码
  • ✅ 只记录是否提供了密码(hasPassword=true/false
  • ✅ 用户ID可以记录(非敏感信息)

异常处理

异常场景

异常情况 HTTP状态码 返回code 返回data.message
用户不存在 200 200 "未查询到用户"
未设置密码 200 200 "用户未设置支付密码"
密码错误 200 200 "密码错误"
系统异常 200 500 "查询失败:{异常信息}"

注意: 所有业务逻辑错误都返回HTTP 200,通过data.data字段判断实际结果。


测试用例

测试场景1: 正常检查(已设置密码)

前置条件:

  • 用户ID=114存在
  • 用户已设置支付密码

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

预期结果:

{
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    }
}

测试场景2: 用户未设置密码

前置条件:

  • 用户ID=114存在
  • 用户未设置支付密码(pay_password为NULL)

请求:

GET /merchantUser/checkPayPassword?storeUserId=114

预期结果:

{
    "data": {
        "code": 200,
        "message": "用户未设置支付密码",
        "data": "false"
    }
}

测试场景3: 用户不存在

前置条件:

  • 用户ID=999999不存在

请求:

GET /merchantUser/checkPayPassword?storeUserId=999999

预期结果:

{
    "data": {
        "code": 200,
        "message": "未查询到用户",
        "data": "false"
    }
}

测试场景4: 密码验证成功

前置条件:

  • 用户ID=114存在
  • 支付密码为"123456"

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=123456

预期结果:

{
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    }
}

测试场景5: 密码验证失败

前置条件:

  • 用户ID=114存在
  • 支付密码为"123456"

请求:

GET /merchantUser/checkPayPassword?storeUserId=114&password=wrong_password

预期结果:

{
    "data": {
        "code": 200,
        "message": "密码错误",
        "data": "false"
    }
}

性能优化

1. 数据库索引

确保 store_user 表的主键有索引:

-- 主键索引(通常自动创建)
ALTER TABLE store_user ADD PRIMARY KEY (id);

2. 查询优化

  • ✅ 使用主键查询(性能最优)
  • ✅ 只查询必要的字段

3. 缓存策略

对于频繁查询的用户信息,可以考虑使用Redis缓存:

// 伪代码示例
String cacheKey = "user:pay_password:" + storeUserId;
String hasPassword = redisTemplate.opsForValue().get(cacheKey);

if (hasPassword == null) {
    // 查询数据库
    StoreUser storeUser = storeUserMapper.selectById(storeUserId);
    hasPassword = storeUser.getPayPassword() != null ? "true" : "false";
    
    // 缓存结果(TTL: 5分钟)
    redisTemplate.opsForValue().set(cacheKey, hasPassword, 5, TimeUnit.MINUTES);
}

注意: 如果使用缓存,在用户设置或修改支付密码时需要清除缓存。


注意事项

1. 返回值格式

⚠️ 特殊格式: 本接口返回的data字段是一个Map对象,而不是简单的布尔值。

// 外层R对象
{
    "code": 200,
    "success": true,
    "data": {              // <- Map对象
        "code": 200,
        "message": "...",
        "data": "true/false"  // <- 字符串,不是布尔值
    }
}

2. 字符串类型

⚠️ data.data 字段的值是字符串类型"true""false"),不是布尔类型。

正确判断:

// ✅ 正确
if (response.data.data.data === "true") { ... }

// ❌ 错误
if (response.data.data.data === true) { ... }

3. 密码安全

⚠️ 强烈建议:

  • 数据库中的密码应该加密存储
  • 传输过程使用HTTPS
  • 添加密码错误次数限制
  • 不在日志中记录明文密码

4. 参数可选性

⚠️ password 参数是可选的:

  • 不提供:只检查是否设置
  • 提供:检查并验证密码

迁移说明

原接口(app端)

  • 服务: alien-store
  • 路径: /alienStore/store/user/havePayPassword
  • Controller: StoreUserController
  • Service: StoreUserService.havePayPassword()

新接口(web端)

  • 服务: alien-store-platform
  • 路径: /merchantUser/checkPayPassword
  • Controller: MerchantUserController
  • Service: MerchantUserService.checkPayPassword()

差异说明

项目 app端 web端 说明
接口路径 /havePayPassword /checkPayPassword 更符合web端命名规范
参数类型 String String 保持一致
返回类型 R<Map> R<Map> 保持一致
业务逻辑 完全复用
日志记录 基础 详细 增强日志记录
登录验证 公开接口

复用的核心组件

  1. Mapper: StoreUserMapper
  2. Entity: StoreUser
  3. 业务逻辑: 完全复用

更新日志

2025-11-17

新增接口:

  • GET /merchantUser/checkPayPassword - 检查是否设置支付密码

核心功能:

  • ✅ 检查用户是否存在
  • ✅ 检查是否设置支付密码
  • ✅ 可选的密码验证功能
  • ✅ 返回统一格式的Map对象
  • ✅ 详细日志记录
  • ✅ 完善异常处理

涉及文件:

  • MerchantUserController.java - 更新
  • MerchantUserService.java - 更新
  • MerchantUserServiceImpl.java - 更新

代码质量:

  • ✅ Linter检查:无错误
  • ✅ 日志记录:详细
  • ✅ 异常处理:完善
  • ✅ 代码注释:完整

开发人员: ssk


文档版本: v1.0
最后更新: 2025-11-17
维护人员: ssk