fix: Add input validation and OAuth client access control

- Add username validation (required, 3-50 chars, alphanumeric + underscore)
    - Add password validation (required, minimum 8 characters)
    - Add email format validation using regex
    - Add owner check in OAuth client update and delete operations
    - Allow admin users with wildcard permission to access all organizations
master
veypi 7 days ago
parent b2b24df82e
commit c588962485

@ -7,6 +7,9 @@
package auth
import (
"regexp"
"strings"
baseauth "github.com/veypi/vbase/auth"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/libs/crypto"
@ -15,6 +18,9 @@ import (
"github.com/veypi/vigo"
)
// Email 正则表达式
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
// RegisterRequest 注册请求
type RegisterRequest struct {
Username string `json:"username" src:"json" desc:"用户名"`
@ -26,6 +32,31 @@ type RegisterRequest struct {
// register 用户注册
func register(x *vigo.X, req *RegisterRequest) (*AuthResponse, error) {
// 验证用户名
if strings.TrimSpace(req.Username) == "" {
return nil, vigo.ErrInvalidArg.WithString("username is required")
}
if len(req.Username) < 3 || len(req.Username) > 50 {
return nil, vigo.ErrInvalidArg.WithString("username must be between 3 and 50 characters")
}
// 用户名只能包含字母、数字和下划线
if !regexp.MustCompile(`^[a-zA-Z0-9_]+$`).MatchString(req.Username) {
return nil, vigo.ErrInvalidArg.WithString("username can only contain letters, numbers and underscores")
}
// 验证密码
if strings.TrimSpace(req.Password) == "" {
return nil, vigo.ErrInvalidArg.WithString("password is required")
}
if len(req.Password) < 8 {
return nil, vigo.ErrInvalidArg.WithString("password must be at least 8 characters")
}
// 验证邮箱格式
if req.Email != "" && !emailRegex.MatchString(req.Email) {
return nil, vigo.ErrInvalidArg.WithString("invalid email format")
}
// 检查注册配置
requireEmail, _ := models.GetSettingBool(models.SettingAuthRegRequireEmail)
requirePhone, _ := models.GetSettingBool(models.SettingAuthRegRequirePhone)

@ -122,6 +122,22 @@ func updateClient(x *vigo.X, req *UpdateClientRequest) (*models.OAuthClient, err
return nil, vigo.ErrNotFound
}
// 检查权限:只有所有者或管理员可以修改
currentUserID := auth.GetUserID(x)
if currentUserID == "" {
return nil, vigo.ErrUnauthorized
}
// 检查是否是所有者
isOwner := client.OwnerID == currentUserID
// 检查是否是管理员(拥有 *:* 权限)
isAdmin := auth.VBaseAuth.CheckPerm(x.Context(), currentUserID, "", "vb:*:*", "")
if !isOwner && !isAdmin {
return nil, vigo.ErrForbidden.WithString("not the owner of this client")
}
updates := make(map[string]any)
if req.Name != nil {
updates["name"] = *req.Name
@ -153,6 +169,22 @@ func deleteClient(x *vigo.X, req *DeleteClientRequest) error {
return vigo.ErrNotFound
}
// 检查权限:只有所有者或管理员可以删除
currentUserID := auth.GetUserID(x)
if currentUserID == "" {
return vigo.ErrUnauthorized
}
// 检查是否是所有者
isOwner := client.OwnerID == currentUserID
// 检查是否是管理员(拥有 *:* 权限)
isAdmin := auth.VBaseAuth.CheckPerm(x.Context(), currentUserID, "", "vb:*:*", "")
if !isOwner && !isAdmin {
return vigo.ErrForbidden.WithString("not the owner of this client")
}
if err := cfg.DB().Delete(&client).Error; err != nil {
return vigo.ErrInternalServer.WithError(err)
}

@ -454,6 +454,13 @@ func (a *appAuth) LoadOrg(x *vigo.X) error {
return vigo.ErrUnauthorized
}
// 检查是否是管理员(拥有 *:* 权限),管理员可以访问所有组织
isAdmin := a.CheckPerm(x.Context(), userID, "", "vb:*:*", "")
if isAdmin {
x.Set(CtxKeyOrgID, orgID)
return nil
}
// 检查用户是否为组织成员
var member models.OrgMember
err := cfg.DB().Where("user_id = ? AND org_id = ? AND status = ?", userID, orgID, models.MemberStatusActive).First(&member).Error

Loading…
Cancel
Save