anxin-ruoyi/.kiro/specs/user-enterprise-identity-verification/design.md

884 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design Document
## Overview
本设计文档描述了用户企业认证、身份认证和员工CA二维码认证功能的技术实现方案。该功能将在现有的若依系统Spring Boot 2.5.15 + MyBatis + Vue3中添加认证能力并实现基于认证状态的权限控制。
系统采用分层架构设计,包括:
- **Controller层**处理HTTP请求和响应
- **Service层**:实现业务逻辑
- **Mapper层**:数据访问层
- **Domain层**:实体模型
- **CA接口适配层**对接外部CA服务
### 企业认证方式
系统采用法人CA认证方式进行企业认证
- 用户提交企业信息和法人身份信息(法人姓名、法人身份证号)
- 系统验证信息完整性和格式
- 系统通过CA接口适配层调用外部CA服务进行法人身份认证
- CA服务验证法人身份与企业的关联关系
- CA认证成功后自动通过企业认证认证状态直接变为"已认证"
- 无需人工审核,实现自动化认证
## Architecture
### 企业认证业务流程
```mermaid
graph TD
A[用户填写企业信息+法人身份信息] --> B[提交法人CA认证申请]
B --> C[系统验证信息完整性]
C -->|验证通过| D[调用CA服务进行法人认证]
C -->|验证失败| E[返回错误信息]
D --> F{CA认证结果}
F -->|认证成功| G[自动通过企业认证]
F -->|认证失败| H[返回CA错误信息]
G --> I[更新状态为"已认证"]
I --> J[记录CA认证ID和时间]
```
### 模块划分
```
ruoyi-system (系统模块)
├── domain
│ ├── UserEnterpriseVerification (用户企业认证实体)
│ ├── UserIdentityVerification (用户身份认证实体)
│ └── VerificationAuditLog (认证审核日志实体)
├── mapper
│ ├── UserEnterpriseVerificationMapper
│ ├── UserIdentityVerificationMapper
│ └── VerificationAuditLogMapper
├── service
│ ├── IUserVerificationService (认证服务接口)
│ └── impl
│ └── UserVerificationServiceImpl
└── controller (在ruoyi-admin中)
└── UserVerificationController
ruoyi-credit (员工管理模块)
├── domain
│ └── EmployeeQRCode (员工实名认证二维码实体)
├── mapper
│ └── EmployeeQRCodeMapper
├── service
│ ├── IEmployeeQRCodeService
│ └── impl
│ └── EmployeeQRCodeServiceImpl
├── ca
│ ├── CAServiceAdapter (CA服务适配器接口)
│ ├── impl
│ │ ├── MockCAServiceAdapter (Mock实现)
│ │ └── RealCAServiceAdapter (真实CA服务实现-预留)
│ └── config
│ └── CAServiceConfig (CA服务配置)
└── controller (在ruoyi-admin中)
└── EmployeeQRCodeController
ruoyi-common (通用模块)
├── utils
│ ├── IdCardValidator (身份证验证工具)
│ ├── QRCodeGenerator (二维码生成工具)
│ └── EncryptionUtil (加密工具)
└── interceptor
└── VerificationInterceptor (认证拦截器)
```
### 技术栈
- **后端框架**: Spring Boot 2.5.15
- **持久层**: MyBatis + MySQL
- **安全框架**: Spring Security
- **加密算法**: AES-256-GCM (身份证号), RSA (二维码签名)
- **二维码生成**: ZXing
- **前端框架**: Vue 3 + Element Plus
- **HTTP客户端**: Apache HttpClient (调用CA服务)
## Components and Interfaces
### 1. 权限常量定义
```java
public class VerificationPermissions {
// 认证查看权限
public static final String VIEW_ALL_VERIFICATION = "system:verification:view:all";
public static final String EXPORT_VERIFICATION = "system:verification:export";
}
```
### 2. 用户认证服务 (UserVerificationService)
#### 接口定义
```java
public interface IUserVerificationService {
// 企业认证 - 法人CA认证方式
AjaxResult submitEnterpriseVerificationWithLegalPersonCA(EnterpriseCAVerificationRequest request);
AjaxResult getEnterpriseVerificationStatus(Long userId);
// 身份认证
AjaxResult submitIdentityVerification(UserIdentityVerification verification);
AjaxResult getIdentityVerificationStatus(Long userId);
// 认证状态查询
boolean isUserFullyVerified(Long userId);
VerificationStatusDTO getUserVerificationStatus(Long userId);
// 企业认证管理
@PreAuthorize("hasAuthority('system:verification:view:all')")
List<UserEnterpriseVerification> listEnterpriseVerifications(VerificationQuery query);
@PreAuthorize("hasAuthority('system:verification:export')")
byte[] exportEnterpriseVerifications(VerificationQuery query);
}
```
#### 法人CA认证请求对象
```java
public class EnterpriseCAVerificationRequest {
private Long userId; // 用户ID
private String enterpriseName; // 企业名称
private String enterpriseCode; // 企业统一社会信用代码
private String legalPersonName; // 法人姓名
private String legalPersonIdCard; // 法人身份证号
private String businessLicense; // 营业执照URL可选
}
```
### 4. CA服务适配器 (CAServiceAdapter)
#### 接口定义
```java
public interface IEmployeeQRCodeService {
// 二维码生成
AjaxResult generateQRCode(Long employeeId);
byte[] getQRCodeImage(String qrCodeId);
// 二维码验证调用CA服务
QRCodeVerificationResult verifyQRCodeWithCA(String qrCodeData);
boolean isQRCodeValid(String qrCodeId);
}
```
#### 二维码数据格式
```java
public class EmployeeQRCodeData {
private Long employeeId; // 员工ID
private String realName; // 真实姓名
private String idCardNumber; // 身份证号(明文)
private Long timestamp; // 时间戳
}
```
### 4. CA服务适配器 (CAServiceAdapter)
#### 接口定义
```java
public interface CAServiceAdapter {
// 身份认证操作
IdentityVerificationResponse verifyIdentity(IdentityVerificationRequest request);
// 健康检查
boolean isServiceAvailable();
}
```
#### CA服务请求/响应格式
```java
// 身份认证请求对象
public class IdentityVerificationRequest {
private String userId; // 用户ID或员工ID
private String realName; // 真实姓名
private String idCardNumber; // 身份证号
private String verificationType; // IDENTITY-身份认证, EMPLOYEE-员工认证, LEGAL_PERSON-法人认证
private String enterpriseName; // 企业名称(法人认证时使用)
private String enterpriseCode; // 企业统一社会信用代码(法人认证时使用)
}
// 身份认证响应对象
public class IdentityVerificationResponse {
private boolean success;
private String verificationId; // CA服务返回的认证ID
private String verificationStatus; // APPROVED-通过, REJECTED-拒绝
private String rejectReason; // 拒绝原因
private Date verificationTime;
private String errorCode;
private String errorMessage;
private Map<String, Object> additionalData; // 额外数据(如法人认证返回的企业信息)
}
```
### 5. 认证拦截器 (VerificationInterceptor)
```java
@Component
public class VerificationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 检查当前用户的认证状态
// 如果访问需要认证的菜单但用户未认证,则拦截
// 超级管理员例外
}
}
```
## Data Models
### 1. 用户企业认证表 (sys_user_enterprise_verification)
```sql
CREATE TABLE sys_user_enterprise_verification (
verification_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '认证ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
enterprise_name VARCHAR(200) NOT NULL COMMENT '企业名称',
enterprise_code VARCHAR(100) NOT NULL COMMENT '企业统一社会信用代码',
legal_person VARCHAR(100) COMMENT '法人代表',
legal_person_id_card VARCHAR(200) COMMENT '法人身份证号(加密)',
business_license VARCHAR(500) COMMENT '营业执照URL',
verification_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '认证状态: PENDING-未认证, APPROVED-已认证, REJECTED-认证失败',
ca_verification_id VARCHAR(100) COMMENT 'CA服务返回的认证ID',
ca_verification_time DATETIME COMMENT 'CA认证时间',
audit_remark VARCHAR(500) COMMENT '备注',
create_by VARCHAR(64) COMMENT '创建者',
create_time DATETIME COMMENT '创建时间',
update_by VARCHAR(64) COMMENT '更新者',
update_time DATETIME COMMENT '更新时间',
INDEX idx_user_id (user_id),
INDEX idx_status (verification_status),
INDEX idx_enterprise_code (enterprise_code),
INDEX idx_ca_verification_id (ca_verification_id)
) COMMENT='用户企业认证表';
```
### 2. 用户身份认证表 (sys_user_identity_verification)
```sql
CREATE TABLE sys_user_identity_verification (
verification_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '认证ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
real_name VARCHAR(100) NOT NULL COMMENT '真实姓名',
id_card_number VARCHAR(200) NOT NULL COMMENT '身份证号(加密)',
verification_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '认证状态: PENDING-未认证, APPROVED-已认证, REJECTED-认证失败',
ca_verification_id VARCHAR(100) COMMENT 'CA服务返回的认证ID',
reject_reason VARCHAR(500) COMMENT 'CA服务拒绝原因',
verification_time DATETIME COMMENT 'CA认证时间',
create_by VARCHAR(64) COMMENT '创建者',
create_time DATETIME COMMENT '创建时间',
update_by VARCHAR(64) COMMENT '更新者',
update_time DATETIME COMMENT '更新时间',
INDEX idx_user_id (user_id),
INDEX idx_status (verification_status),
INDEX idx_ca_verification_id (ca_verification_id)
) COMMENT='用户身份认证表';
```
### 3. 认证审核日志表 (sys_verification_audit_log)
```sql
CREATE TABLE sys_verification_audit_log (
log_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '日志ID',
verification_type VARCHAR(20) NOT NULL COMMENT '认证类型: ENTERPRISE-企业认证, IDENTITY-身份认证',
verification_id BIGINT NOT NULL COMMENT '认证记录ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
old_status VARCHAR(20) COMMENT '原状态',
new_status VARCHAR(20) NOT NULL COMMENT '新状态',
audit_remark VARCHAR(500) COMMENT '审核备注',
operator_id BIGINT NOT NULL COMMENT '操作人ID',
operator_name VARCHAR(100) COMMENT '操作人姓名',
operator_roles VARCHAR(200) COMMENT '操作人角色列表(逗号分隔)',
operation_time DATETIME NOT NULL COMMENT '操作时间',
INDEX idx_verification (verification_type, verification_id),
INDEX idx_user_id (user_id),
INDEX idx_operation_time (operation_time),
INDEX idx_operator_id (operator_id)
) COMMENT='认证审核日志表';
```
### 4. 员工实名认证二维码表 (dc_employee_qr_code)
```sql
CREATE TABLE dc_employee_qr_code (
qr_code_id VARCHAR(64) PRIMARY KEY COMMENT '二维码ID(UUID)',
employee_id BIGINT NOT NULL COMMENT '员工ID',
real_name VARCHAR(100) NOT NULL COMMENT '真实姓名',
id_card_number VARCHAR(18) NOT NULL COMMENT '身份证号',
generate_time DATETIME NOT NULL COMMENT '生成时间',
expiry_time DATETIME NOT NULL COMMENT '过期时间',
qr_code_status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '二维码状态: ACTIVE-有效, EXPIRED-已过期, USED-已使用',
verification_status VARCHAR(20) COMMENT '认证状态: PENDING-待认证, APPROVED-已认证, REJECTED-认证失败',
ca_verification_id VARCHAR(100) COMMENT 'CA服务返回的认证ID',
verification_time DATETIME COMMENT '认证时间',
INDEX idx_employee_id (employee_id),
INDEX idx_status (qr_code_status),
INDEX idx_expiry_time (expiry_time)
) COMMENT='员工实名认证二维码表';
```
### 5. CA服务配置表 (sys_ca_service_config)
```sql
CREATE TABLE sys_ca_service_config (
config_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '配置ID',
config_key VARCHAR(100) NOT NULL UNIQUE COMMENT '配置键',
config_value VARCHAR(500) NOT NULL COMMENT '配置值',
config_desc VARCHAR(200) COMMENT '配置描述',
is_encrypted TINYINT(1) DEFAULT 0 COMMENT '是否加密存储',
create_time DATETIME COMMENT '创建时间',
update_time DATETIME COMMENT '更新时间'
) COMMENT='CA服务配置表';
-- 初始化配置数据
INSERT INTO sys_ca_service_config (config_key, config_value, config_desc) VALUES
('ca.service.url', 'http://localhost:8080/mock-ca', 'CA服务接口地址'),
('ca.service.timeout', '30000', 'CA服务超时时间(毫秒)'),
('ca.service.app_id', 'ruoyi-system', 'CA服务应用ID'),
('ca.service.app_secret', 'mock-secret-key', 'CA服务应用密钥'),
('ca.service.enabled', 'true', 'CA服务是否启用'),
('ca.qrcode.validity_hours', '24', '二维码默认有效期(小时)');
```
### 7. 角色和权限初始化
```sql
-- 插入认证审核员角色
INSERT INTO sys_role (role_name, role_key, role_sort, status, del_flag, create_time, remark) VALUES
('认证审核员', 'verification_auditor', 3, '0', '0', NOW(), '负责审核企业认证申请');
-- 插入认证管理员角色
INSERT INTO sys_role (role_name, role_key, role_sort, status, del_flag, create_time, remark) VALUES
('认证管理员', 'verification_manager', 2, '0', '0', NOW(), '负责管理所有认证信息');
-- 插入认证相关菜单权限
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_time, remark) VALUES
('认证管理', 0, 5, 'verification', NULL, 1, 'M', '0', '0', NULL, 'shield', NOW(), '认证管理目录'),
('企业认证审核', (SELECT menu_id FROM sys_menu WHERE menu_name='认证管理'), 1, 'enterprise', 'system/verification/enterprise', 1, 'C', '0', '0', 'system:verification:audit:enterprise', 'building', NOW(), '企业认证审核菜单'),
('认证信息管理', (SELECT menu_id FROM sys_menu WHERE menu_name='认证管理'), 2, 'manage', 'system/verification/manage', 1, 'C', '0', '0', 'system:verification:manage', 'list', NOW(), '认证信息管理菜单');
-- 为认证审核员角色分配权限
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT r.role_id, m.menu_id
FROM sys_role r, sys_menu m
WHERE r.role_key = 'verification_auditor'
AND m.perms IN ('system:verification:audit:enterprise', 'system:verification:view:all');
-- 为认证管理员角色分配权限
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT r.role_id, m.menu_id
FROM sys_role r, sys_menu m
WHERE r.role_key = 'verification_manager'
AND m.perms IN ('system:verification:audit:enterprise', 'system:verification:manage', 'system:verification:view:all', 'system:verification:export');
```
## Correctness Properties
*属性是一个特征或行为,应该在系统的所有有效执行中保持为真——本质上是关于系统应该做什么的正式陈述。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*
### 企业认证属性
Property 1: 企业认证信息验证
*For any* 企业认证申请,如果企业信息和法人身份信息完整且格式正确,则系统应该接受申请并返回成功
**Validates: Requirements 1.2**
Property 2: 法人CA认证调用
*For any* 有效的法人CA认证申请系统应该通过CA接口适配层调用外部CA服务进行法人身份认证
**Validates: Requirements 1.3**
Property 3: 法人CA认证成功处理
*For any* CA服务返回法人认证成功的响应系统应该自动通过企业认证并更新认证状态为"已认证"
**Validates: Requirements 1.4**
Property 4: 法人CA认证失败处理
*For any* CA服务返回法人认证失败的响应系统应该返回具体错误信息并保持认证状态为"未认证"
**Validates: Requirements 1.5**
Property 5: 法人CA认证记录
*For any* 法人CA认证通过系统应该记录CA认证ID、认证时间和法人身份信息
**Validates: Requirements 1.6**
Property 6: 企业认证重新申请
*For any* 被拒绝的企业认证,用户应该能够重新提交申请
**Validates: Requirements 1.7**
### 身份认证属性
Property 7: 身份证号格式验证
*For any* 18位身份证号系统应该验证其格式和校验位的正确性
**Validates: Requirements 2.4**
Property 8: 身份证号加密存储
*For any* 有效的身份证号存储后应该是加密的且解密后应该等于原始值round-trip property
**Validates: Requirements 2.6, 7.1**
Property 9: CA服务身份认证调用
*For any* 有效的身份认证申请系统应该通过CA接口适配层调用外部CA服务进行身份认证
**Validates: Requirements 2.5**
Property 10: CA身份认证成功处理
*For any* CA服务返回认证成功的响应系统应该更新认证状态为"已认证"并记录CA认证ID和时间
**Validates: Requirements 2.6**
Property 11: CA身份认证失败处理
*For any* CA服务返回认证失败的响应系统应该更新认证状态为"认证失败"并记录拒绝原因
**Validates: Requirements 2.7**
### 员工实名认证二维码属性
Property 12: 二维码内容完整性
*For any* 员工生成的实名认证二维码应该包含员工ID、真实姓名、身份证号和时间戳
**Validates: Requirements 3.1**
Property 13: 二维码CA认证调用
*For any* 有效的二维码扫描后系统应该调用CA服务进行身份认证
**Validates: Requirements 3.3**
Property 14: 二维码认证成功处理
*For any* CA服务返回认证成功的响应系统应该更新员工认证状态为"已认证"并记录认证时间
**Validates: Requirements 3.4**
Property 15: 二维码认证失败处理
*For any* CA服务返回认证失败的响应系统应该返回具体失败原因并保持认证状态为"未认证"
**Validates: Requirements 3.5**
Property 16: 二维码过期验证
*For any* 超过有效期的二维码,系统应该拒绝认证并提示重新生成
**Validates: Requirements 3.6, 4.6**
### CA服务接口属性
Property 17: CA服务配置读取
*For any* CA服务调用系统应该从配置文件读取接口地址和认证信息
**Validates: Requirements 4.2**
Property 18: CA服务错误处理
*For any* CA服务不可用的情况系统应该返回友好的错误信息并记录日志
**Validates: Requirements 4.3**
Property 19: CA服务超时处理
*For any* CA服务调用如果30秒内未响应系统应该超时并返回错误信息
**Validates: Requirements 4.6**
Property 20: CA服务调用日志
*For any* CA服务调用系统应该记录请求参数、响应结果和调用时间
**Validates: Requirements 4.7**
### 权限控制属性
Property 21: 未认证用户访问拦截
*For any* 未完成双认证的普通用户,访问需要认证的功能时应该被拦截并显示认证提示
**Validates: Requirements 5.1, 5.3**
Property 22: 双认证完成解除限制
*For any* 完成企业认证和身份认证的用户,应该能够访问所有需要认证的功能
**Validates: Requirements 5.4**
Property 23: 超级管理员特殊权限
*For any* 超级管理员用户userId=1即使未认证也应该能够访问所有功能
**Validates: Requirements 5.5**
Property 24: 权限检查双认证状态
*For any* 权限检查操作,系统应该验证用户的企业认证和身份认证状态都为"已认证"
**Validates: Requirements 5.8**
Property 25: 认证菜单配置化
*For any* 配置为需要认证的菜单,系统应该根据配置文件进行权限控制
**Validates: Requirements 5.9**
### 数据安全属性
Property 26: 认证数据访问权限
*For any* 认证数据访问操作,系统应该验证用户权限并记录访问日志
**Validates: Requirements 7.3**
Property 27: 法人身份证号加密存储
*For any* 有效的法人身份证号存储后应该是加密的且解密后应该等于原始值round-trip property
**Validates: Requirements 7.1**
## Error Handling
### 1. 输入验证错误
- **企业信息不完整**: 返回缺失字段列表
- **企业统一社会信用代码格式错误**: 返回格式说明
- **身份证号格式错误**: 返回格式说明和校验位错误提示
- **身份证号校验位错误**: 返回校验位计算说明
### 2. 业务逻辑错误
- **重复提交认证申请**: 提示已有待审核的申请
- **认证状态不允许操作**: 提示当前状态和允许的操作
- **二维码已过期**: 提示二维码已过期,需要重新生成
- **二维码签名验证失败**: 提示二维码无效
### 3. 外部服务错误
- **CA服务不可用**: 返回友好提示,建议稍后重试,记录详细错误日志
- **CA服务超时**: 返回超时提示,记录超时日志
- **CA服务返回错误**: 解析错误码,返回对应的中文提示
### 4. 系统错误
- **加密/解密失败**: 记录错误日志,返回通用错误提示
- **数据库操作失败**: 记录错误日志,返回通用错误提示
- **二维码生成失败**: 记录错误日志,返回生成失败提示
### 错误码设计
```java
public enum VerificationErrorCode {
// 输入验证错误 (1000-1999)
INVALID_ENTERPRISE_INFO(1001, "企业信息不完整或格式错误"),
INVALID_ID_CARD_FORMAT(1002, "身份证号格式错误"),
INVALID_ID_CARD_CHECKSUM(1003, "身份证号校验位错误"),
// 业务逻辑错误 (2000-2999)
DUPLICATE_VERIFICATION(2001, "已有待审核的认证申请"),
INVALID_VERIFICATION_STATUS(2002, "当前认证状态不允许此操作"),
QRCODE_EXPIRED(2006, "二维码已过期"),
QRCODE_INVALID_SIGNATURE(2007, "二维码签名验证失败"),
// 外部服务错误 (3000-3999)
CA_SERVICE_UNAVAILABLE(3001, "CA服务暂时不可用请稍后重试"),
CA_SERVICE_TIMEOUT(3002, "CA服务响应超时"),
CA_SERVICE_ERROR(3003, "CA服务返回错误"),
// 系统错误 (9000-9999)
ENCRYPTION_ERROR(9001, "数据加密失败"),
DECRYPTION_ERROR(9002, "数据解密失败"),
DATABASE_ERROR(9003, "数据库操作失败"),
QRCODE_GENERATION_ERROR(9004, "二维码生成失败");
private final int code;
private final String message;
VerificationErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
}
```
## Testing Strategy
### 单元测试
使用JUnit 5进行单元测试覆盖以下内容
1. **工具类测试**
- IdCardValidator: 测试身份证号验证逻辑
- EncryptionUtil: 测试加密解密功能
- QRCodeGenerator: 测试二维码生成功能
2. **Service层测试**
- UserVerificationService: 测试认证业务逻辑
- EmployeeCACertificateService: 测试CA证书管理逻辑
- EmployeeQRCodeService: 测试二维码生成和验证逻辑
3. **CA适配器测试**
- MockCAServiceAdapter: 测试Mock实现
- CAServiceConfig: 测试配置读取
### 属性测试
使用jqwik进行属性测试每个测试至少运行100次迭代
1. **认证属性测试**
- 测试Property 1-8: 企业认证和身份认证的各种属性
- 生成随机的认证数据,验证系统行为
2. **CA证书属性测试**
- 测试Property 9-13: CA证书管理的各种属性
- 生成随机的员工和证书数据,验证证书生命周期
3. **二维码属性测试**
- 测试Property 14-18: 二维码生成和验证的各种属性
- 生成随机的二维码数据,验证签名和验证逻辑
4. **权限控制属性测试**
- 测试Property 23-27: 权限控制的各种属性
- 生成随机的用户和认证状态,验证权限拦截逻辑
5. **加密属性测试**
- 测试Property 7, 15, 28: 加密和签名的round-trip属性
- 生成随机的数据,验证加密解密和签名验证的正确性
### 集成测试
1. **Controller层集成测试**
- 使用MockMvc测试API接口
- 测试请求参数验证、响应格式、错误处理
2. **数据库集成测试**
- 使用H2内存数据库进行测试
- 测试Mapper层的CRUD操作
3. **CA服务集成测试**
- 使用MockCAServiceAdapter进行测试
- 测试CA服务调用、超时处理、错误处理
### 前端测试
1. **组件测试**
- 使用Vitest测试Vue组件
- 测试认证表单、认证状态显示、二维码显示
2. **E2E测试**
- 使用Playwright测试完整的认证流程
- 测试用户提交认证、管理员审核、权限控制
### 测试覆盖率目标
- 单元测试代码覆盖率: ≥ 80%
- 属性测试: 覆盖所有定义的正确性属性
- 集成测试: 覆盖所有API接口
- E2E测试: 覆盖主要业务流程
## Implementation Notes
### 1. 加密实现
使用BouncyCastle库实现AES-256-GCM加密
```java
public class EncryptionUtil {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int GCM_TAG_LENGTH = 128;
private static final int GCM_IV_LENGTH = 12;
public static String encrypt(String plaintext, SecretKey key) {
// 实现AES-256-GCM加密
}
public static String decrypt(String ciphertext, SecretKey key) {
// 实现AES-256-GCM解密
}
}
```
### 2. 身份证号验证
实现GB 11643-1999标准的身份证号验证
```java
public class IdCardValidator {
private static final int[] WEIGHT = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
private static final char[] CHECK_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
public static boolean validate(String idCard) {
// 验证长度、格式、校验位
}
}
```
### 3. 二维码生成
使用ZXing库生成二维码
```java
public class QRCodeGenerator {
public static byte[] generateQRCode(String content, int width, int height) {
// 使用ZXing生成二维码图片
}
}
```
### 4. CA服务适配器配置
在application.yml中配置CA服务
```yaml
ca:
service:
enabled: true
adapter: mock # mock 或 real
url: http://localhost:8080/mock-ca
timeout: 30000
app-id: ruoyi-system
app-secret: ${CA_APP_SECRET:mock-secret-key}
certificate:
validity-days: 365
qrcode:
validity-hours: 24
```
### 5. 权限拦截器配置
在WebMvcConfigurer中注册拦截器
```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private VerificationInterceptor verificationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(verificationInterceptor)
.addPathPatterns("/credit/contract/**") // 需要认证的路径
.excludePathPatterns("/system/user/verification/**"); // 排除认证接口本身
}
}
```
### 6. 定时任务
使用Spring的@Scheduled注解实现CA证书过期提醒
```java
@Component
public class CertificateExpiryTask {
@Scheduled(cron = "0 0 9 * * ?") // 每天早上9点执行
public void checkExpiringCertificates() {
// 查询30天内过期的证书
// 发送过期提醒通知
}
}
```
### 7. 前端界面实现
#### 企业认证提交
```vue
<template>
<el-dialog title="企业认证" v-model="dialogVisible">
<!-- 法人CA认证表单 -->
<el-form :model="caForm" ref="caFormRef">
<el-form-item label="企业名称" prop="enterpriseName" required>
<el-input v-model="caForm.enterpriseName" />
</el-form-item>
<el-form-item label="统一社会信用代码" prop="enterpriseCode" required>
<el-input v-model="caForm.enterpriseCode" />
</el-form-item>
<el-form-item label="法人姓名" prop="legalPersonName" required>
<el-input v-model="caForm.legalPersonName" />
</el-form-item>
<el-form-item label="法人身份证号" prop="legalPersonIdCard" required>
<el-input v-model="caForm.legalPersonIdCard" maxlength="18" />
</el-form-item>
<el-form-item label="营业执照" prop="businessLicense">
<el-upload action="/api/upload" :on-success="handleUploadSuccess">
<el-button>上传营业执照(可选)</el-button>
</el-upload>
</el-form-item>
<el-alert
title="法人CA认证说明"
type="info"
:closable="false"
description="系统将通过CA服务验证法人身份与企业的关联关系认证成功后自动完成企业认证。"
/>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitVerification" :loading="submitting">
提交认证
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue';
import { submitEnterpriseVerificationWithCA } from '@/api/verification';
const caForm = ref({
enterpriseName: '',
enterpriseCode: '',
legalPersonName: '',
legalPersonIdCard: '',
businessLicense: ''
});
const submitVerification = async () => {
await submitEnterpriseVerificationWithCA(caForm.value);
};
</script>
```
在Vue Router中添加路由守卫
```javascript
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresVerification) {
const verificationStatus = await getVerificationStatus();
if (!verificationStatus.isFullyVerified && !verificationStatus.isSuperAdmin) {
// 显示认证提示横幅
showVerificationBanner();
// 阻止访问
next(false);
} else {
next();
}
} else {
next();
}
});
```
### 8. 前端路由守卫
在Vue Router中添加路由守卫
```javascript
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresVerification) {
const verificationStatus = await getVerificationStatus();
if (!verificationStatus.isFullyVerified && !verificationStatus.isSuperAdmin) {
// 显示认证提示横幅
showVerificationBanner();
// 阻止访问
next(false);
} else {
next();
}
} else {
next();
}
});
```
## Deployment Considerations
### 1. 数据库迁移
使用Flyway或Liquibase管理数据库版本
- V1__create_verification_tables.sql: 创建认证相关表
- V2__create_ca_certificate_tables.sql: 创建CA证书相关表
- V3__init_ca_service_config.sql: 初始化CA服务配置
### 2. 密钥管理
- AES加密密钥: 使用环境变量或密钥管理服务如AWS KMS
- RSA密钥对: 生成后安全存储,定期轮换
- CA服务密钥: 加密存储在配置表中
### 3. 性能优化
- 认证状态缓存: 使用Redis缓存用户认证状态减少数据库查询
- 二维码图片缓存: 缓存生成的二维码图片
- CA服务调用: 实现重试机制和熔断器
### 4. 监控和告警
- CA服务可用性监控
- 证书过期监控
- 认证申请量监控
- 错误率监控
### 5. 安全加固
- 限制认证申请频率(防止滥用)
- 审核操作需要二次确认
- 敏感操作记录审计日志
- 定期备份认证数据