feat(api-key): 添加 IP 白名单/黑名单限制功能 (#221)
* feat(api-key): add IP whitelist/blacklist restriction and usage log IP tracking - Add IP restriction feature for API keys (whitelist/blacklist with CIDR support) - Add IP address logging to usage logs (admin-only visibility) - Remove billing_type column from usage logs UI (redundant) - Use generic "Access denied" error message for security Backend: - New ip package with IP/CIDR validation and matching utilities - Database migrations for ip_whitelist, ip_blacklist (api_keys) and ip_address (usage_logs) - Middleware IP restriction check after API key validation - Input validation for IP/CIDR patterns on create/update Frontend: - API key form with enable toggle for IP restriction - Shield icon indicator in table for keys with IP restriction - Removed billing_type filter and column from usage views * fix: update API contract tests for ip_whitelist/ip_blacklist fields Add ip_whitelist and ip_blacklist fields to expected JSON responses in API contract tests to match the new API key schema.
This commit is contained in:
@@ -337,6 +337,20 @@ func (_c *UsageLogCreate) SetNillableUserAgent(v *string) *UsageLogCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetIPAddress sets the "ip_address" field.
|
||||
func (_c *UsageLogCreate) SetIPAddress(v string) *UsageLogCreate {
|
||||
_c.mutation.SetIPAddress(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableIPAddress sets the "ip_address" field if the given value is not nil.
|
||||
func (_c *UsageLogCreate) SetNillableIPAddress(v *string) *UsageLogCreate {
|
||||
if v != nil {
|
||||
_c.SetIPAddress(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (_c *UsageLogCreate) SetImageCount(v int) *UsageLogCreate {
|
||||
_c.mutation.SetImageCount(v)
|
||||
@@ -586,6 +600,11 @@ func (_c *UsageLogCreate) check() error {
|
||||
return &ValidationError{Name: "user_agent", err: fmt.Errorf(`ent: validator failed for field "UsageLog.user_agent": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _c.mutation.IPAddress(); ok {
|
||||
if err := usagelog.IPAddressValidator(v); err != nil {
|
||||
return &ValidationError{Name: "ip_address", err: fmt.Errorf(`ent: validator failed for field "UsageLog.ip_address": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _, ok := _c.mutation.ImageCount(); !ok {
|
||||
return &ValidationError{Name: "image_count", err: errors.New(`ent: missing required field "UsageLog.image_count"`)}
|
||||
}
|
||||
@@ -713,6 +732,10 @@ func (_c *UsageLogCreate) createSpec() (*UsageLog, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(usagelog.FieldUserAgent, field.TypeString, value)
|
||||
_node.UserAgent = &value
|
||||
}
|
||||
if value, ok := _c.mutation.IPAddress(); ok {
|
||||
_spec.SetField(usagelog.FieldIPAddress, field.TypeString, value)
|
||||
_node.IPAddress = &value
|
||||
}
|
||||
if value, ok := _c.mutation.ImageCount(); ok {
|
||||
_spec.SetField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
_node.ImageCount = value
|
||||
@@ -1288,6 +1311,24 @@ func (u *UsageLogUpsert) ClearUserAgent() *UsageLogUpsert {
|
||||
return u
|
||||
}
|
||||
|
||||
// SetIPAddress sets the "ip_address" field.
|
||||
func (u *UsageLogUpsert) SetIPAddress(v string) *UsageLogUpsert {
|
||||
u.Set(usagelog.FieldIPAddress, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateIPAddress sets the "ip_address" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsert) UpdateIPAddress() *UsageLogUpsert {
|
||||
u.SetExcluded(usagelog.FieldIPAddress)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearIPAddress clears the value of the "ip_address" field.
|
||||
func (u *UsageLogUpsert) ClearIPAddress() *UsageLogUpsert {
|
||||
u.SetNull(usagelog.FieldIPAddress)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsert) SetImageCount(v int) *UsageLogUpsert {
|
||||
u.Set(usagelog.FieldImageCount, v)
|
||||
@@ -1866,6 +1907,27 @@ func (u *UsageLogUpsertOne) ClearUserAgent() *UsageLogUpsertOne {
|
||||
})
|
||||
}
|
||||
|
||||
// SetIPAddress sets the "ip_address" field.
|
||||
func (u *UsageLogUpsertOne) SetIPAddress(v string) *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetIPAddress(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateIPAddress sets the "ip_address" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertOne) UpdateIPAddress() *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateIPAddress()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearIPAddress clears the value of the "ip_address" field.
|
||||
func (u *UsageLogUpsertOne) ClearIPAddress() *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.ClearIPAddress()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsertOne) SetImageCount(v int) *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
@@ -2616,6 +2678,27 @@ func (u *UsageLogUpsertBulk) ClearUserAgent() *UsageLogUpsertBulk {
|
||||
})
|
||||
}
|
||||
|
||||
// SetIPAddress sets the "ip_address" field.
|
||||
func (u *UsageLogUpsertBulk) SetIPAddress(v string) *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetIPAddress(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateIPAddress sets the "ip_address" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertBulk) UpdateIPAddress() *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateIPAddress()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearIPAddress clears the value of the "ip_address" field.
|
||||
func (u *UsageLogUpsertBulk) ClearIPAddress() *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.ClearIPAddress()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsertBulk) SetImageCount(v int) *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
|
||||
Reference in New Issue
Block a user