# IP限制API

<cite>
**本文档引用文件**   
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go)
- [restriction.go](file://internal/service/restriction.go)
- [restriction.go](file://internal/logic/restriction/restriction.go)
- [v_1_restrict_ip_order_access.go](file://internal/dao/v_1_restrict_ip_order_access.go)
- [v_1_restrict_ip_record.go](file://internal/dao/v_1_restrict_ip_record.go)
- [entity.go](file://internal/model/entity/v_1_restrict_ip_order_access.go)
- [do.go](file://internal/model/do/v_1_restrict_ip_order_access.go)
- [restriction.go](file://internal/model/restriction.go)
- [restriction.go](file://internal/consts/restriction.go)
- [cache.go](file://utility/cache/cache.go)
</cite>

## 目录
1. [简介](#简介)
2. [核心功能](#核心功能)
3. [IP访问控制端点](#ip访问控制端点)
4. [IP匹配算法](#ip匹配算法)
5. [缓存策略](#缓存策略)
6. [数据库设计](#数据库设计)
7. [错误处理](#错误处理)
8. [性能优化](#性能优化)
9. [集成关系](#集成关系)
10. [客户端调用示例](#客户端调用示例)
11. [常见问题](#常见问题)

## 简介
IP限制API提供了一套完整的IP访问控制机制，用于管理系统对特定IP地址的访问权限。该系统支持基于商户部署策略的多维度限制，包括IP、设备、卡密和代理检测等多种控制方式。系统通过Redis缓存和数据库持久化相结合的方式，实现了高性能的IP状态管理。

## 核心功能
IP限制系统提供以下核心功能：
- IP白名单/黑名单管理
- 基于省份的区域访问控制
- 设备级访问限制
- 卡密关联的访问控制
- 代理使用检测
- 访问记录持久化存储

**IP限制核心功能组件关系图**

```mermaid
graph TD
A[API控制器] --> B[服务接口]
B --> C[业务逻辑]
C --> D[数据访问层]
D --> E[数据库]
C --> F[Redis缓存]
G[商户部署策略] --> C
H[IP匹配算法] --> C
I[访问记录] --> D
```

**图示来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [restriction.go](file://internal/service/restriction.go#L1-L67)
- [restriction.go](file://internal/logic/restriction/restriction.go#L1-L174)

## IP访问控制端点

### 端点信息
- **HTTP方法**: POST
- **URL模式**: `/api/restriction/v1/check_ip_allowed`
- **认证机制**: 基于商户部署ID的认证
- **权限控制**: 通过商户部署策略配置的限制规则

### 请求参数
请求体包含以下字段：
- `orderNo`: 订单号
- `ip`: 待检查的IP地址
- `deviceId`: 设备ID
- `cardPass`: 卡密
- `merchantDeployID`: 商户部署ID

### 响应结构
响应体包含以下字段：
- `isAllowed`: 布尔值，表示IP是否被允许访问

### 访问控制流程
```mermaid
flowchart TD
Start([开始]) --> GetStrategy["获取商户限制策略"]
GetStrategy --> StrategyValid{"策略有效?"}
StrategyValid --> |否| ReturnError["返回内部错误"]
StrategyValid --> |是| CheckCardPass["检查卡密限制"]
CheckCardPass --> CardPassRestricted{"卡密受限?"}
CardPassRestricted --> |是| ReturnFalse["返回不允许"]
CardPassRestricted --> |否| CheckDevice["检查设备限制"]
CheckDevice --> DeviceRestricted{"设备受限?"}
DeviceRestricted --> |是| ReturnFalse
DeviceRestricted --> |否| CheckProxy["检查代理使用"]
CheckProxy --> ProxyUsed{"使用代理?"}
ProxyUsed --> |是| ReturnFalse
ProxyUsed --> |否| CheckPublicIP["检查公网IP"]
CheckPublicIP --> IsPublic{"公网IP?"}
IsPublic --> |是| CheckIPExist["检查IP是否受限"]
IsPublic --> |否| CheckInternalIP["检查内网IP策略"]
CheckInternalIP --> RestrictInternal{"限制内网IP?"}
RestrictInternal --> |是| ReturnFalse
RestrictInternal --> |否| ReturnTrue["返回允许"]
CheckIPExist --> IPExist{"IP受限?"}
IPExist --> |是| ReturnFalse
IPExist --> |否| CheckArea["检查区域限制"]
CheckArea --> AreaConfigured{"配置区域?"}
AreaConfigured --> |是| CheckAreaAllowed["检查IP是否在允许区域"]
AreaConfigured --> |否| ReturnTrue
CheckAreaAllowed --> AreaAllowed{"在允许区域?"}
AreaAllowed --> |是| ReturnTrue
AreaAllowed --> |否| ReturnFalse
ReturnTrue --> End([结束])
ReturnFalse --> End
```

**图示来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)

**本节来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)

## IP匹配算法

### 算法实现
IP匹配算法主要通过`CheckIPIsAllowed`和`IsInProvince`方法实现，其核心逻辑如下：

```mermaid
flowchart TD
Start([开始]) --> ParseIP["解析IP地址"]
ParseIP --> IsPublicIP["判断是否为公网IP"]
IsPublicIP --> |否| ReturnTrue["返回允许"]
IsPublicIP --> |是| GetIPRecord["获取IP记录"]
GetIPRecord --> RecordExist{"记录存在?"}
RecordExist --> |否| ReturnFalse["返回不允许"]
RecordExist --> |是| IsPublic{"公网地址?"}
IsPublic --> |否| ReturnFalse
IsPublic --> |是| CheckProvince["检查省份"]
CheckProvince --> IsAlpha{"英文省份?"}
IsAlpha --> |是| ConvertToPinyin["转换为拼音"]
IsAlpha --> |否| CompareProvince["直接比较"]
ConvertToPinyin --> CompareProvince
CompareProvince --> InProvince{"在允许省份?"}
InProvince --> |是| ReturnTrue
InProvince --> |否| CheckOverseas["检查海外"]
CheckOverseas --> IsOverseas{"是海外?"}
IsOverseas --> |是| ReturnTrue
IsOverseas --> |否| ReturnFalse
ReturnTrue --> End([结束])
ReturnFalse --> End
```

**图示来源**
- [restriction.go](file://internal/logic/restriction/restriction.go#L30-L65)

### 省份匹配逻辑
系统支持34个省级行政区的匹配，包括：
- 23个省
- 5个自治区
- 4个直辖市
- 2个特别行政区

匹配时支持中文和拼音两种格式，系统会自动进行转换和匹配。

**本节来源**
- [restriction.go](file://internal/logic/restriction/restriction.go#L30-L65)
- [consts.go](file://utility/integration/restriction/consts.go#L17-L23)

## 缓存策略

### Redis缓存实现
系统使用Redis作为缓存层，通过`utility/cache/cache.go`文件中的`Cache`结构体实现缓存操作。

```mermaid
classDiagram
class Cache {
+*gcache.Cache
+Incr(ctx, key, duration)
+Decr(ctx, key, duration)
+GetPrefixKeyNum(ctx, key)
+SaveTrace(ctx, key)
+GetTrace(ctx, key)
+GetTraceID(ctx)
+DeleteTrace(ctx, key)
}
class PrefixEnum {
+RedeemType
+RedeemWithPaymentType
+RedeemAppleAccountLimitedType
+AccountLimiterType
+JDAccountQueryCache
+JDAccountQueryBalanceWithCookie
+WalmartAccountQueryCache
+WalmartAccountQueryBalanceWithCookie
+AppleMachineAccount
+AppleDuplicatedOrder
+PrefixTrace
+Key(key)
}
Cache --> PrefixEnum : "使用"
```

**图示来源**
- [cache.go](file://utility/cache/cache.go#L1-L127)

### 缓存键设计
系统采用前缀+键的设计模式，主要缓存键包括：
- `redeem_type`: 兑换类型缓存
- `account_limiter_type`: 账户限流类型
- `jd_account_query_cache`: 京东账户查询缓存
- `walmart_account_query_cache`: 沃尔玛账户查询缓存
- `apple_duplicated_order`: 苹果重复订单
- `trace`: 追踪信息

**本节来源**
- [cache.go](file://utility/cache/cache.go#L1-L127)

## 数据库设计

### 核心表结构
系统使用两个核心表来存储IP限制相关信息：

#### 限制IP记录表 (restrict_ip_record)
| 字段名 | 类型 | 描述 |
|--------|------|------|
| id | uint | 主键 |
| ip | string | IP地址 |
| ip_province | string | IP所在省份 |
| is_public | bool | 是否为公网地址 |
| raw_data | string | 原始数据 |
| created_at | *gtime.Time | 创建时间 |
| updated_at | *gtime.Time | 更新时间 |
| deleted_at | *gtime.Time | 删除时间 |

#### IP订单访问表 (restrict_ip_order_access)
| 字段名 | 类型 | 描述 |
|--------|------|------|
| id | uint | 主键 |
| restrict_ip_id | int | 关联的IP地址 |
| order_no | string | 订单号 |
| card_pass | string | 卡密 |
| ip | string | IP地址 |
| status | int | 状态 |
| restrict_strategy | string | 限制策略 |
| device_id | string | 设备ID |
| created_at | *gtime.Time | 创建时间 |
| updated_at | *gtime.Time | 更新时间 |
| deleted_at | *gtime.Time | 删除时间 |

### 表关系
```mermaid
erDiagram
V1RestrictIpRecord ||--o{ V1RestrictIpOrderAccess : "包含"
V1RestrictIpRecord {
uint id PK
string ip
string ip_province
bool is_public
string raw_data
*gtime.Time created_at
*gtime.Time updated_at
*gtime.Time deleted_at
}
V1RestrictIpOrderAccess {
uint id PK
int restrict_ip_id FK
string order_no
string card_pass
string ip
int status
string restrict_strategy
string device_id
*gtime.Time created_at
*gtime.Time updated_at
*gtime.Time deleted_at
}
```

**图示来源**
- [v_1_restrict_ip_record.go](file://internal/dao/v_1_restrict_ip_record.go#L1-L28)
- [v_1_restrict_ip_order_access.go](file://internal/dao/v_1_restrict_ip_order_access.go#L1-L27)
- [entity.go](file://internal/model/entity/v_1_restrict_ip_record.go#L1-L22)
- [entity.go](file://internal/model/entity/v_1_restrict_ip_order_access.go#L1-L25)

**本节来源**
- [v_1_restrict_ip_record.go](file://internal/dao/v_1_restrict_ip_record.go#L1-L28)
- [v_1_restrict_ip_order_access.go](file://internal/dao/v_1_restrict_ip_order_access.go#L1-L27)

## 错误处理

### 错误处理机制
系统采用统一的错误处理机制，主要通过`errHandler`包实现。

```mermaid
sequenceDiagram
participant Client as "客户端"
participant Controller as "控制器"
participant Service as "服务层"
participant Logic as "业务逻辑"
Client->>Controller : 发送请求
Controller->>Service : 调用服务
Service->>Logic : 执行业务逻辑
alt 执行成功
Logic-->>Service : 返回结果
Service-->>Controller : 返回结果
Controller-->>Client : 返回成功响应
else 执行失败
Logic--xService : 抛出错误
Service--xController : 包装错误
Controller-->>Client : 返回错误响应
end
```

**图示来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [restriction.go](file://internal/service/restriction.go#L1-L67)

### 错误码
系统定义了以下错误码：
- `gcode.CodeInternalError`: 内部错误，当获取限制策略失败时返回

**本节来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [errHandler.go](file://internal/errHandler/handler.go)

## 性能优化

### 事务处理
系统在添加IP限制记录时使用数据库事务，确保数据一致性：

```go
err = config.GetDatabaseV1().Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
    // 事务内的操作
    return nil
})
```

### 缓存优化
系统通过Redis缓存频繁访问的数据，减少数据库查询次数。

### 并发处理
在省份匹配时，系统使用并发处理提高性能：

```go
slice.ForEachConcurrent(allProvinceListCopier, func(index int, item string) {
    allProvinceListCopier[index] = gstr.ToLower(pinyin.NewDict().Convert(item, "").None())
}, 5)
```

**本节来源**
- [restriction.go](file://internal/logic/restriction/restriction.go#L67-L174)
- [cache.go](file://utility/cache/cache.go#L1-L127)

## 集成关系

### 系统集成架构
```mermaid
graph TD
A[前端应用] --> B[API网关]
B --> C[IP限制API]
C --> D[商户部署服务]
C --> E[订单服务]
C --> F[Redis缓存]
C --> G[数据库]
D --> H[配置中心]
E --> I[支付服务]
G --> J[备份系统]
subgraph "核心服务"
C
D
E
end
subgraph "数据存储"
F
G
J
end
```

**图示来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [restriction.go](file://internal/service/restriction.go#L1-L67)

### 依赖服务
IP限制API依赖以下服务：
- 商户部署信息服务：获取限制策略
- 订单服务：更新订单状态
- Redis服务：缓存IP状态
- 数据库服务：持久化存储访问记录

**本节来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [restriction.go](file://internal/service/restriction.go#L1-L67)

## 客户端调用示例

### Go语言调用示例
```go
// 创建请求
req := &v1.CheckIPAllowedReq{
    OrderNo:         "ORDER123456",
    Ip:              "192.168.1.1",
    DeviceId:        "DEVICE789",
    CardPass:        "CARDPASS001",
    MerchantDeployID: 1,
}

// 调用API
res, err := controller.CheckIPAllowed(context.Background(), req)
if err != nil {
    log.Printf("检查IP失败: %v", err)
    return
}

// 处理结果
if res.IsAllowed {
    fmt.Println("IP允许访问")
} else {
    fmt.Println("IP被限制访问")
}
```

### HTTP调用示例
```bash
curl -X POST https://api.example.com/api/restriction/v1/check_ip_allowed \
  -H "Content-Type: application/json" \
  -d '{
    "orderNo": "ORDER123456",
    "ip": "192.168.1.1",
    "deviceId": "DEVICE789",
    "cardPass": "CARDPASS001",
    "merchantDeployID": 1
  }'
```

**本节来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)

## 常见问题

### Q1: 如何配置IP白名单？
A: IP白名单通过商户部署策略中的`RestrictArea`字段配置，系统会检查IP是否在允许的区域内。

### Q2: 内网IP如何处理？
A: 系统会检测IP是否为内网IP，如果配置了`IsRestrictInternalIp`为false，则允许内网IP访问。

### Q3: 如何查看IP限制记录？
A: 可以通过`GetRestrictRecordByIP`方法查询特定IP的所有限制记录。

### Q4: 系统如何处理代理？
A: 系统通过`CheckIsDeviceUseProxy`方法检测设备是否使用代理，如果检测到使用代理且策略要求限制，则拒绝访问。

### Q5: 缓存失效时间如何设置？
A: 系统使用Redis默认的缓存策略，具体失效时间根据不同的缓存键而定。

**本节来源**
- [restriction_v1_check_ip_allowed.go](file://internal/controller/restriction/restriction_v1_check_ip_allowed.go#L1-L70)
- [restriction.go](file://internal/service/restriction.go#L1-L67)
- [restriction.go](file://internal/logic/restriction/restriction.go#L1-L174)