Files
tyapi-server/internal/shared/validator/AUTH_DATE_VALIDATOR.md
2025-07-28 01:46:39 +08:00

246 lines
5.4 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.

# AuthDate 授权日期验证器
## 概述
`authDate` 是一个自定义验证器,用于验证授权日期格式和有效性。该验证器确保日期格式正确,并且日期范围必须包括今天。
## 验证规则
### 1. 格式要求
- 必须为 `YYYYMMDD-YYYYMMDD` 格式
- 两个日期之间用连字符 `-` 分隔
- 每个日期必须是8位数字
### 2. 日期有效性
- 开始日期不能晚于结束日期
- 日期范围必须包括今天(如果两个日期都是今天也行)
- 支持闰年验证
- 验证月份和日期的有效性
### 3. 业务逻辑
- 空值由 `required` 标签处理,本验证器返回 `true`
- 日期范围必须覆盖今天,确保授权在有效期内
## 使用示例
### 在 DTO 中使用
```go
type FLXG0V4BReq struct {
Name string `json:"name" validate:"required,name"`
IDCard string `json:"id_card" validate:"required,idCard"`
AuthDate string `json:"auth_date" validate:"required,authDate"`
}
```
### 在结构体中使用
```go
type AuthorizationRequest struct {
UserID string `json:"user_id" validate:"required"`
AuthDate string `json:"auth_date" validate:"required,authDate"`
Scope string `json:"scope" validate:"required"`
}
```
## 有效示例
### ✅ 有效的日期范围
```json
{
"auth_date": "20240101-20240131" // 1月1日到1月31日如果今天是1月15日
}
```
```json
{
"auth_date": "20240115-20240115" // 今天到今天
}
```
```json
{
"auth_date": "20240110-20240120" // 昨天到明天如果今天是1月15日
}
```
```json
{
"auth_date": "20240101-20240201" // 上个月到下个月如果今天是1月15日
}
```
### ❌ 无效的日期范围
```json
{
"auth_date": "20240116-20240120" // 明天到后天(不包括今天)
}
```
```json
{
"auth_date": "20240101-20240114" // 上个月到昨天(不包括今天)
}
```
```json
{
"auth_date": "20240131-20240101" // 开始日期晚于结束日期
}
```
```json
{
"auth_date": "20240101-2024013A" // 非数字字符
}
```
```json
{
"auth_date": "202401-20240131" // 日期长度不对
}
```
```json
{
"auth_date": "2024010120240131" // 缺少连字符
}
```
```json
{
"auth_date": "20240230-20240301" // 无效日期2月30日
}
```
## 错误消息
当验证失败时,会返回中文错误消息:
```
"授权日期格式不正确必须是YYYYMMDD-YYYYMMDD格式且日期范围必须包括今天"
```
## 测试用例
验证器包含完整的测试用例,覆盖以下场景:
### 有效场景
- 今天到今天
- 昨天到今天
- 今天到明天
- 上周到今天
- 今天到下周
- 昨天到明天
### 无效场景
- 明天到后天(不包括今天)
- 上周到昨天(不包括今天)
- 格式错误(缺少连字符、多个连字符、长度不对、非数字)
- 无效日期2月30日、13月等
- 开始日期晚于结束日期
## 实现细节
### 核心验证逻辑
```go
func validateAuthDate(fl validator.FieldLevel) bool {
authDate := fl.Field().String()
if authDate == "" {
return true // 空值由required标签处理
}
// 1. 检查格式YYYYMMDD-YYYYMMDD
parts := strings.Split(authDate, "-")
if len(parts) != 2 {
return false
}
// 2. 解析日期
startDate, err := parseYYYYMMDD(parts[0])
if err != nil {
return false
}
endDate, err := parseYYYYMMDD(parts[1])
if err != nil {
return false
}
// 3. 检查日期顺序
if startDate.After(endDate) {
return false
}
// 4. 检查是否包括今天
today := time.Now().Truncate(24 * time.Hour)
return !startDate.After(today) && !endDate.Before(today)
}
```
### 日期解析
```go
func parseYYYYMMDD(dateStr string) (time.Time, error) {
if len(dateStr) != 8 {
return time.Time{}, fmt.Errorf("日期格式错误")
}
year, _ := strconv.Atoi(dateStr[:4])
month, _ := strconv.Atoi(dateStr[4:6])
day, _ := strconv.Atoi(dateStr[6:8])
date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
// 验证日期有效性
expectedDateStr := date.Format("20060102")
if expectedDateStr != dateStr {
return time.Time{}, fmt.Errorf("无效日期")
}
return date, nil
}
```
## 注册方式
验证器已在 `RegisterCustomValidators` 函数中自动注册:
```go
func RegisterCustomValidators(validate *validator.Validate) {
// ... 其他验证器
validate.RegisterValidation("auth_date", validateAuthDate)
}
```
翻译也已自动注册:
```go
validate.RegisterTranslation("auth_date", trans, func(ut ut.Translator) error {
return ut.Add("auth_date", "{0}格式不正确必须是YYYYMMDD-YYYYMMDD格式且日期范围必须包括今天", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("auth_date", getFieldDisplayName(fe.Field()))
return t
})
```
## 注意事项
1. **时区处理**:验证器使用 UTC 时区进行日期比较
2. **空值处理**:空字符串由 `required` 标签处理,本验证器返回 `true`
3. **日期精度**:只比较日期部分,忽略时间部分
4. **闰年支持**:自动处理闰年验证
5. **错误消息**:提供中文错误消息,便于用户理解
## 运行测试
```bash
# 运行所有 authDate 相关测试
go test ./internal/shared/validator -v -run TestValidateAuthDate
# 运行所有验证器测试
go test ./internal/shared/validator -v
```