fix: 生产安全修复 + Go SDK + CAS SSO框架

安全修复:
- CRITICAL: SSO重定向URL注入漏洞 - 修复redirect_uri白名单验证
- HIGH: SSO ClientSecret未验证 - 使用crypto/subtle.ConstantTimeCompare验证
- HIGH: 邮件验证码熵值过低(3字节) - 提升到6字节(48位熵)
- HIGH: 短信验证码熵值过低(4字节) - 提升到6字节
- HIGH: Goroutine使用已取消上下文 - auth_email.go使用独立context+超时
- HIGH: SQL LIKE查询注入风险 - permission/role仓库使用escapeLikePattern

新功能:
- Go SDK: sdk/go/user-management/ 完整SDK实现
- CAS SSO框架: internal/auth/cas.go CAS协议支持

其他:
- L1Cache实例问题修复 - AuthMiddleware共享l1Cache
- 设备指纹XSS防护 - 内存存储替代localStorage
- 响应格式协议中间件
- 导出无界查询修复
This commit is contained in:
2026-04-03 17:38:31 +08:00
parent 44e60be918
commit 765a50b7d4
22 changed files with 2318 additions and 71 deletions

View File

@@ -0,0 +1,157 @@
package userManagement
import (
"context"
"fmt"
)
// CreateRoleRequest 创建角色请求
type CreateRoleRequest struct {
Name string `json:"name"`
Code string `json:"code"`
Description string `json:"description,omitempty"`
PermissionIDs []int64 `json:"permission_ids,omitempty"`
Status RoleStatus `json:"status,omitempty"`
}
// UpdateRoleRequest 更新角色请求
type UpdateRoleRequest struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
PermissionIDs []int64 `json:"permission_ids,omitempty"`
Status RoleStatus `json:"status,omitempty"`
}
// ListRolesParams 角色列表查询参数
type ListRolesParams struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Keyword string `json:"keyword,omitempty"`
Status string `json:"status,omitempty"`
}
// GetRole 获取角色详情
func (c *Client) GetRole(ctx context.Context, id int64) (*Role, error) {
resp, err := c.doRequest(ctx, "GET", fmt.Sprintf("/api/v1/roles/%d", id), nil)
if err != nil {
return nil, err
}
var result Role
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return &result, nil
}
// ListRoles 获取角色列表
func (c *Client) ListRoles(ctx context.Context, params *ListRolesParams) (*PaginatedResponse, error) {
if params.Page <= 0 {
params.Page = 1
}
if params.PageSize <= 0 {
params.PageSize = 20
}
path := fmt.Sprintf("/api/v1/roles?page=%d&page_size=%d", params.Page, params.PageSize)
if params.Keyword != "" {
path += "&keyword=" + params.Keyword
}
if params.Status != "" {
path += "&status=" + params.Status
}
resp, err := c.doRequest(ctx, "GET", path, nil)
if err != nil {
return nil, err
}
var result PaginatedResponse
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return &result, nil
}
// CreateRole 创建角色
func (c *Client) CreateRole(ctx context.Context, req *CreateRoleRequest) (*Role, error) {
resp, err := c.doRequest(ctx, "POST", "/api/v1/roles", req)
if err != nil {
return nil, err
}
var result Role
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return &result, nil
}
// UpdateRole 更新角色
func (c *Client) UpdateRole(ctx context.Context, id int64, req *UpdateRoleRequest) (*Role, error) {
resp, err := c.doRequest(ctx, "PUT", fmt.Sprintf("/api/v1/roles/%d", id), req)
if err != nil {
return nil, err
}
var result Role
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return &result, nil
}
// DeleteRole 删除角色
func (c *Client) DeleteRole(ctx context.Context, id int64) error {
resp, err := c.doRequest(ctx, "DELETE", fmt.Sprintf("/api/v1/roles/%d", id), nil)
if err != nil {
return err
}
return c.parseResponse(resp, nil)
}
// AssignPermissions 分配权限给角色
func (c *Client) AssignPermissions(ctx context.Context, roleID int64, permissionIDs []int64) error {
req := map[string][]int64{"permission_ids": permissionIDs}
resp, err := c.doRequest(ctx, "POST", fmt.Sprintf("/api/v1/roles/%d/permissions", roleID), req)
if err != nil {
return err
}
return c.parseResponse(resp, nil)
}
// GetRolePermissions 获取角色权限
func (c *Client) GetRolePermissions(ctx context.Context, roleID int64) ([]*Permission, error) {
resp, err := c.doRequest(ctx, "GET", fmt.Sprintf("/api/v1/roles/%d/permissions", roleID), nil)
if err != nil {
return nil, err
}
var result []*Permission
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return result, nil
}
// ListPermissions 获取权限列表(树形)
func (c *Client) ListPermissions(ctx context.Context) ([]*Permission, error) {
resp, err := c.doRequest(ctx, "GET", "/api/v1/permissions", nil)
if err != nil {
return nil, err
}
var result []*Permission
if err := c.parseResponse(resp, &result); err != nil {
return nil, err
}
return result, nil
}