优化客服云权限安全与访客IP解析
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -779,6 +781,91 @@ func TestCustomerAndStatisticsDataScopesPreventCrossAgentAccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingsAndExportsHonorFineGrainedPermissions(t *testing.T) {
|
||||
router := setupRouter(t)
|
||||
tenant := createTenant(t, "细粒度权限租户", "normal")
|
||||
admin := createUser(t, tenant.ID, "fine-admin", "admin")
|
||||
seed := httptest.NewRecorder()
|
||||
router.ServeHTTP(seed, bearerRequest(t, http.MethodGet, "/api/roles", nil, admin))
|
||||
if seed.Code != http.StatusOK {
|
||||
t.Fatalf("初始化权限数据失败: %d %s", seed.Code, seed.Body.String())
|
||||
}
|
||||
createRole := httptest.NewRecorder()
|
||||
roleBody := []byte(`{"name":"只读设置导出","permissions":["settings.basic","customer.view","customer.export","chat_history.view","chat_history.export"],"data_scopes":{"customer":"self","chat_history":"self"}}`)
|
||||
router.ServeHTTP(createRole, bearerRequest(t, http.MethodPost, "/api/roles", roleBody, admin))
|
||||
if createRole.Code != http.StatusOK {
|
||||
t.Fatalf("创建测试角色失败: %d %s", createRole.Code, createRole.Body.String())
|
||||
}
|
||||
var roleResp struct {
|
||||
Data model.Role `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(createRole.Body.Bytes(), &roleResp); err != nil {
|
||||
t.Fatalf("解析测试角色失败: %v", err)
|
||||
}
|
||||
operator := createUser(t, tenant.ID, "fine-operator", roleResp.Data.Code)
|
||||
|
||||
settings := httptest.NewRecorder()
|
||||
router.ServeHTTP(settings, bearerRequest(t, http.MethodPut, "/api/settings", []byte(`{"assign_strategy":"round_robin"}`), operator))
|
||||
if settings.Code != http.StatusForbidden {
|
||||
t.Fatalf("缺少分配规则权限仍可修改设置: %d %s", settings.Code, settings.Body.String())
|
||||
}
|
||||
|
||||
customerOne := model.Customer{TenantID: tenant.ID, Name: "客户一"}
|
||||
customerTwo := model.Customer{TenantID: tenant.ID, Name: "客户二"}
|
||||
if err := model.DB.Create(&customerOne).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := model.DB.Create(&customerTwo).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sessionOne := model.Session{TenantID: tenant.ID, CustomerID: customerOne.ID, AgentID: &operator.ID, Status: "ended"}
|
||||
other := createUser(t, tenant.ID, "fine-other", "agent")
|
||||
sessionTwo := model.Session{TenantID: tenant.ID, CustomerID: customerTwo.ID, AgentID: &other.ID, Status: "ended"}
|
||||
if err := model.DB.Create(&sessionOne).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := model.DB.Create(&sessionTwo).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
customerExport := httptest.NewRecorder()
|
||||
router.ServeHTTP(customerExport, bearerRequest(t, http.MethodGet, "/api/customers/export", nil, operator))
|
||||
if customerExport.Code != http.StatusOK || strings.Contains(customerExport.Body.String(), "客户二") {
|
||||
t.Fatalf("客户导出越过 customer=self 范围: %d %s", customerExport.Code, customerExport.Body.String())
|
||||
}
|
||||
sessionExport := httptest.NewRecorder()
|
||||
router.ServeHTTP(sessionExport, bearerRequest(t, http.MethodGet, "/api/sessions/export", nil, operator))
|
||||
if sessionExport.Code != http.StatusOK || strings.Contains(sessionExport.Body.String(), ","+strconv.FormatUint(uint64(sessionTwo.ID), 10)+",") {
|
||||
t.Fatalf("会话导出越过 chat_history=self 范围: %d %s", sessionExport.Code, sessionExport.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomerExportPermissionDoesNotGrantDelete(t *testing.T) {
|
||||
router := setupRouter(t)
|
||||
tenant := createTenant(t, "删除权限租户", "normal")
|
||||
admin := createUser(t, tenant.ID, "delete-admin", "admin")
|
||||
seed := httptest.NewRecorder()
|
||||
router.ServeHTTP(seed, bearerRequest(t, http.MethodGet, "/api/roles", nil, admin))
|
||||
createRole := httptest.NewRecorder()
|
||||
router.ServeHTTP(createRole, bearerRequest(t, http.MethodPost, "/api/roles", []byte(`{"name":"仅导出","permissions":["customer.view","customer.export"]}`), admin))
|
||||
var roleResp struct {
|
||||
Data model.Role `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(createRole.Body.Bytes(), &roleResp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
operator := createUser(t, tenant.ID, "export-only", roleResp.Data.Code)
|
||||
customer := model.Customer{TenantID: tenant.ID, Name: "不可删除客户"}
|
||||
if err := model.DB.Create(&customer).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rec := httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, bearerRequest(t, http.MethodDelete, "/api/customers/"+strconv.FormatUint(uint64(customer.ID), 10), nil, operator))
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Fatalf("仅导出角色可删除客户: %d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomerAndKnowledgeCRUD(t *testing.T) {
|
||||
router := setupRouter(t)
|
||||
tenant := createTenant(t, "业务CRUD租户", "normal")
|
||||
|
||||
Reference in New Issue
Block a user