refactor: Migrate auth to Vigo auth interface and simplify initialization

- Replace GetUserID/GetOrgID with VBaseAuth.UserID/OrgID methods across all APIs
- Integrate vigoauth.Auth interface into appAuth for standard auth methods
- Move AuthMiddleware to PermLogin method in auth package
- Add role management methods: GetRole, ListRoles, GrantRoles, RevokeRoles, ListUserRoles
- Update ListUserPermissions and ListResourceUsers to return vigoauth types
- Export Redis client in cfg package
- Simplify app initialization by separating vigo.New in cli/main.go
- Remove deprecated auth/middleware.go file
master
veypi 5 days ago
parent df0f7f047a
commit ec47bcc192

@ -33,7 +33,7 @@ type UserInfoWithPerms struct {
// me 获取当前用户信息 // me 获取当前用户信息
func me(x *vigo.X) (*UserInfoWithPerms, error) { func me(x *vigo.X) (*UserInfoWithPerms, error) {
userID := baseAuth.GetUserID(x) userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }
@ -43,7 +43,7 @@ func me(x *vigo.X) (*UserInfoWithPerms, error) {
return nil, vigo.ErrNotFound return nil, vigo.ErrNotFound
} }
orgID := baseAuth.GetOrgID(x) orgID := baseAuth.VBaseAuth.OrgID(x)
// 获取用户权限列表 // 获取用户权限列表
perms, err := baseAuth.VBaseAuth.ListUserPermissions(x.Context(), userID, orgID) perms, err := baseAuth.VBaseAuth.ListUserPermissions(x.Context(), userID, orgID)
@ -51,11 +51,13 @@ func me(x *vigo.X) (*UserInfoWithPerms, error) {
return nil, vigo.ErrInternalServer.WithError(err) return nil, vigo.ErrInternalServer.WithError(err)
} }
// 转换权限格式 // 转换权限格式 (Vigo 接口返回 vigoauth.UserPermission需要转换回 PermissionID 格式)
userPerms := make([]UserPermissionInfo, 0, len(perms)) userPerms := make([]UserPermissionInfo, 0, len(perms))
for _, p := range perms { for _, p := range perms {
// 从 Resource 构造 PermissionID格式为 vb:resource:*
permissionID := "vb:" + p.Resource + ":*"
userPerms = append(userPerms, UserPermissionInfo{ userPerms = append(userPerms, UserPermissionInfo{
PermissionID: p.PermissionID, PermissionID: permissionID,
ResourceID: p.ResourceID, ResourceID: p.ResourceID,
}) })
} }
@ -87,7 +89,7 @@ type UpdateMeRequest struct {
// updateMe 更新当前用户信息 // updateMe 更新当前用户信息
func updateMe(x *vigo.X, req *UpdateMeRequest) (*UserInfoWithPerms, error) { func updateMe(x *vigo.X, req *UpdateMeRequest) (*UserInfoWithPerms, error) {
userID := baseAuth.GetUserID(x) userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }
@ -124,7 +126,7 @@ type ChangePasswordRequest struct {
// changePassword 修改密码 // changePassword 修改密码
func changePassword(x *vigo.X, req *ChangePasswordRequest) error { func changePassword(x *vigo.X, req *ChangePasswordRequest) error {
userID := baseAuth.GetUserID(x) userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }

@ -83,7 +83,7 @@ func authorizeThirdParty(x *vigo.X, req *AuthorizeRequest) (*AuthorizeResponse,
// 如果是绑定模式,需要当前用户登录 // 如果是绑定模式,需要当前用户登录
if req.BindMode { if req.BindMode {
userID := baseauth.GetUserID(x) userID := baseauth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized.WithString("login required for bind mode") return nil, vigo.ErrUnauthorized.WithString("login required for bind mode")
} }
@ -318,7 +318,7 @@ type UnbindRequest struct {
// unbindThirdParty 解除第三方账号绑定 // unbindThirdParty 解除第三方账号绑定
func unbindThirdParty(x *vigo.X, req *UnbindRequest) error { func unbindThirdParty(x *vigo.X, req *UnbindRequest) error {
userID := baseauth.GetUserID(x) userID := baseauth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
@ -342,7 +342,7 @@ type BindingInfo struct {
// listBindings 获取当前用户的第三方绑定列表 // listBindings 获取当前用户的第三方绑定列表
func listBindings(x *vigo.X) ([]BindingInfo, error) { func listBindings(x *vigo.X) ([]BindingInfo, error) {
userID := baseauth.GetUserID(x) userID := baseauth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }

@ -23,7 +23,7 @@ var Router = vigo.NewRouter()
func init() { func init() {
// 注册全局中间件 // 注册全局中间件
Router.Use(auth.AuthMiddleware()) Router.Use(auth.VBaseAuth.PermLogin)
Router.After(common.JsonResponse, common.JsonErrorResponse) Router.After(common.JsonResponse, common.JsonErrorResponse)
// 子路由挂载 // 子路由挂载

@ -40,7 +40,7 @@ func authorize(x *vigo.X, req *AuthorizeRequest) (*AuthorizeResponse, error) {
} }
// 获取当前用户 // 获取当前用户
userID := auth.GetUserID(x) userID := auth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }

@ -66,7 +66,7 @@ type CreateClientResponse struct {
} }
func createClient(x *vigo.X, req *CreateClientRequest) (*CreateClientResponse, error) { func createClient(x *vigo.X, req *CreateClientRequest) (*CreateClientResponse, error) {
ownerID := auth.GetUserID(x) ownerID := auth.VBaseAuth.UserID(x)
if ownerID == "" { if ownerID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }
@ -123,7 +123,7 @@ func updateClient(x *vigo.X, req *UpdateClientRequest) (*models.OAuthClient, err
} }
// 检查权限:只有所有者或管理员可以修改 // 检查权限:只有所有者或管理员可以修改
currentUserID := auth.GetUserID(x) currentUserID := auth.VBaseAuth.UserID(x)
if currentUserID == "" { if currentUserID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }
@ -170,7 +170,7 @@ func deleteClient(x *vigo.X, req *DeleteClientRequest) error {
} }
// 检查权限:只有所有者或管理员可以删除 // 检查权限:只有所有者或管理员可以删除
currentUserID := auth.GetUserID(x) currentUserID := auth.VBaseAuth.UserID(x)
if currentUserID == "" { if currentUserID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }

@ -14,7 +14,7 @@ import (
// UserInfo OIDC用户信息 // UserInfo OIDC用户信息
func userInfo(x *vigo.X) (map[string]any, error) { func userInfo(x *vigo.X) (map[string]any, error) {
// 从token中解析用户ID // 从token中解析用户ID
userID := auth.GetUserID(x) userID := auth.VBaseAuth.UserID(x)
if userID == "" { if userID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }

@ -28,7 +28,7 @@ func create(x *vigo.X, req *CreateRequest) (*models.Org, error) {
} }
// 获取当前用户ID作为所有者 // 获取当前用户ID作为所有者
ownerID := auth.GetUserID(x) ownerID := auth.VBaseAuth.UserID(x)
if ownerID == "" { if ownerID == "" {
return nil, vigo.ErrUnauthorized return nil, vigo.ErrUnauthorized
} }

@ -21,9 +21,9 @@ type GetRequest struct {
// get 获取用户详情 // get 获取用户详情
func get(x *vigo.X, req *GetRequest) (*models.User, error) { func get(x *vigo.X, req *GetRequest) (*models.User, error) {
// 手动鉴权: 只能查看自己的信息,或者是管理员 // 手动鉴权: 只能查看自己的信息,或者是管理员
uid := auth.GetUserID(x) uid := auth.VBaseAuth.UserID(x)
if uid != req.UserID { if uid != req.UserID {
if !auth.VBaseAuth.CheckPerm(x.Context(), uid, auth.GetOrgID(x), "user:read", "") { if !auth.VBaseAuth.CheckPerm(x.Context(), uid, auth.VBaseAuth.OrgID(x), "user:read", "") {
return nil, vigo.ErrForbidden return nil, vigo.ErrForbidden
} }
} }

@ -25,9 +25,9 @@ type PatchRequest struct {
// patch 更新用户 // patch 更新用户
func patch(x *vigo.X, req *PatchRequest) (*models.User, error) { func patch(x *vigo.X, req *PatchRequest) (*models.User, error) {
// 手动鉴权: 只能修改自己的信息,或者是管理员 // 手动鉴权: 只能修改自己的信息,或者是管理员
uid := auth.GetUserID(x) uid := auth.VBaseAuth.UserID(x)
if uid != req.UserID { if uid != req.UserID {
if !auth.VBaseAuth.CheckPerm(x.Context(), uid, auth.GetOrgID(x), "user:update", "") { if !auth.VBaseAuth.CheckPerm(x.Context(), uid, auth.VBaseAuth.OrgID(x), "user:update", "") {
return nil, vigo.ErrForbidden return nil, vigo.ErrForbidden
} }
} }

@ -16,8 +16,10 @@ import (
"github.com/veypi/vbase/cfg" "github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/libs/cache" "github.com/veypi/vbase/libs/cache"
"github.com/veypi/vbase/libs/jwt"
"github.com/veypi/vbase/models" "github.com/veypi/vbase/models"
"github.com/veypi/vigo" "github.com/veypi/vigo"
vigoauth "github.com/veypi/vigo/contrib/auth"
"github.com/veypi/vigo/contrib/event" "github.com/veypi/vigo/contrib/event"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -36,79 +38,40 @@ const (
RoleCodeUser = "user" RoleCodeUser = "user"
) )
// ========== 辅助函数 ========== // ========== Token 提取 ==========
func GetUserID(x *vigo.X) string {
if userID, ok := x.Get(CtxKeyUserID).(string); ok {
return userID
}
return ""
}
func GetOrgID(x *vigo.X) string { // extractToken 从 Header 或 Query 中提取 JWT token
if orgID, ok := x.Get(CtxKeyOrgID).(string); ok { func extractToken(x *vigo.X) string {
return orgID auth := x.Request.Header.Get("Authorization")
if auth != "" {
if len(auth) > 7 && strings.HasPrefix(auth, "Bearer ") {
return auth[7:]
}
} }
return "" return x.Request.URL.Query().Get("access_token")
} }
func GetOrgRoles(x *vigo.X) []string { // getOrgID 从请求中提取组织ID (Header/Query/Path)
if roles, ok := x.Get(CtxKeyOrgRoles).([]string); ok { func getOrgID(x *vigo.X) string {
return roles orgID := x.Request.Header.Get("X-Org-ID")
if orgID == "" {
orgID = x.Request.URL.Query().Get("org_id")
} }
return nil if orgID == "" {
orgID = x.PathParams.Get("org_id")
}
return orgID
} }
// Auth 权限管理接口 // Auth 权限管理接口 (继承 Vigo auth.Auth 并扩展 LoadOrg)
// 注意appAuth 同时实现了此接口和 vigoauth.Auth 接口
type Auth interface { type Auth interface {
UserID(x *vigo.X) string vigoauth.Auth
OrgID(x *vigo.X) string
// 加载组织信息 (中间件/手动调用) // 加载组织信息 (中间件/手动调用)
LoadOrg(x *vigo.X) error LoadOrg(x *vigo.X) error
// ========== 中间件生成 ========== // 检查权限 (兼容旧接口)
// 基础权限检查
Perm(permissionID string) func(*vigo.X) error
// 特定资源权限检查 (自动从 Path/Query 获取资源ID)
PermOnResource(permissionID, resourceKey string) func(*vigo.X) error
// 满足任一权限
PermAny(permissionIDs ...string) func(*vigo.X) error
// 满足所有权限
PermAll(permissionIDs ...string) func(*vigo.X) error
// ========== 角色管理 ==========
// 添加角色定义
// policies 格式: "resource:action",例如 "user:read", "*:*"
AddRole(roleCode, roleName string, policies ...string) error
// ========== 权限管理 ==========
// 授予角色
GrantRole(ctx context.Context, userID, orgID, roleCode string) error
// 撤销角色
RevokeRole(ctx context.Context, userID, orgID, roleCode string) error
// 授予特定资源权限
GrantResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error
// 撤销特定资源权限
RevokeResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error
// 撤销用户所有权限
RevokeAll(ctx context.Context, userID, orgID string) error
// ========== 权限查询 ==========
// 检查权限
CheckPermission(ctx context.Context, userID, orgID, permissionID, resourceID string) bool CheckPermission(ctx context.Context, userID, orgID, permissionID, resourceID string) bool
CheckPerm(ctx context.Context, userID, orgID, permissionID, resourceID string) bool
// 列出用户权限
ListUserPermissions(ctx context.Context, userID, orgID string) ([]models.UserPermissionResult, error)
// 列出资源授权用户
ListResourceUsers(ctx context.Context, orgID, permissionID, resourceID string) ([]models.ResourceUser, error)
} }
// 全局 Auth 工厂 // 全局 Auth 工厂
@ -262,6 +225,64 @@ func (a *appAuth) AddRole(roleCode, roleName string, policies ...string) error {
return nil return nil
} }
// GetRole 获取角色定义
func (a *appAuth) GetRole(roleCode string) (*vigoauth.Role, error) {
roleDef, exists := a.roleDefs[roleCode]
if !exists {
return nil, fmt.Errorf("role not found: %s", roleCode)
}
// 从数据库获取完整角色信息
var role models.Role
err := cfg.DB().Where("code = ? AND org_id IS NULL", roleCode).First(&role).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("role not found: %s", roleCode)
}
return nil, err
}
// 转换策略为 Vigo 格式
policies := make([]string, 0)
if rolePolicies, ok := a.policies[roleCode]; ok {
for _, p := range rolePolicies {
policies = append(policies, fmt.Sprintf("%s:%s", p[0], p[1]))
}
}
return &vigoauth.Role{
Code: roleDef.code,
Name: roleDef.name,
Policies: policies,
Description: roleDef.description,
}, nil
}
// ListRoles 列出所有角色定义
func (a *appAuth) ListRoles() ([]*vigoauth.Role, error) {
result := make([]*vigoauth.Role, 0)
for code, roleDef := range a.roleDefs {
if code == "_app_info" {
continue
}
policies := make([]string, 0)
if rolePolicies, ok := a.policies[code]; ok {
for _, p := range rolePolicies {
policies = append(policies, fmt.Sprintf("%s:%s", p[0], p[1]))
}
}
result = append(result, &vigoauth.Role{
Code: roleDef.code,
Name: roleDef.name,
Policies: policies,
Description: roleDef.description,
})
}
return result, nil
}
// init 初始化应用的权限配置 // init 初始化应用的权限配置
func (a *appAuth) init() error { func (a *appAuth) init() error {
// 1. 同步权限定义到数据库 // 1. 同步权限定义到数据库
@ -427,29 +448,59 @@ func (a *appAuth) initRole(roleCode string) error {
// ========== 中间件实现 ========== // ========== 中间件实现 ==========
// PermLogin JWT 认证中间件
// 解析 token、验证黑名单、设置 CtxKeyUserID
func (a *appAuth) PermLogin(x *vigo.X) error {
// 1. 提取 token
tokenString := extractToken(x)
if tokenString == "" {
return vigo.ErrUnauthorized.WithString("missing token")
}
// 2. 解析 token
claims, err := jwt.ParseToken(tokenString)
if err != nil {
if err == jwt.ErrExpiredToken {
return vigo.ErrTokenExpired
}
return vigo.ErrTokenInvalid
}
// 3. 检查 token 黑名单
if cache.IsEnabled() {
blacklisted, _ := cache.IsTokenBlacklisted(claims.ID)
if blacklisted {
return vigo.ErrUnauthorized.WithString("token has been revoked")
}
}
// 4. 设置用户ID到上下文
x.Set(CtxKeyUserID, claims.UserID)
return nil
}
func (a *appAuth) UserID(x *vigo.X) string { func (a *appAuth) UserID(x *vigo.X) string {
return GetUserID(x) if userID, ok := x.Get(CtxKeyUserID).(string); ok {
return userID
}
return ""
} }
func (a *appAuth) OrgID(x *vigo.X) string { func (a *appAuth) OrgID(x *vigo.X) string {
return GetOrgID(x) if orgID, ok := x.Get(CtxKeyOrgID).(string); ok {
return orgID
}
return ""
} }
// LoadOrg 加载组织信息
func (a *appAuth) LoadOrg(x *vigo.X) error { func (a *appAuth) LoadOrg(x *vigo.X) error {
orgID := x.Request.Header.Get("X-Org-ID") orgID := getOrgID(x)
if orgID == "" { if orgID == "" {
orgID = x.Request.URL.Query().Get("org_id")
}
if orgID == "" {
orgID = x.PathParams.Get("org_id")
}
if orgID == "" {
// 没有指定组织
return vigo.ErrInvalidArg.WithString("missing org_id") return vigo.ErrInvalidArg.WithString("missing org_id")
} }
userID := GetUserID(x) userID := a.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
@ -478,13 +529,12 @@ func (a *appAuth) LoadOrg(x *vigo.X) error {
func (a *appAuth) Perm(permissionID string) func(*vigo.X) error { func (a *appAuth) Perm(permissionID string) func(*vigo.X) error {
validatePermissionID(permissionID) validatePermissionID(permissionID)
return func(x *vigo.X) error { return func(x *vigo.X) error {
userID := GetUserID(x) userID := a.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
orgID := GetOrgID(x) if err := a.checkPermission(x.Context(), userID, "", permissionID, ""); err != nil {
if err := a.checkPermission(x.Context(), userID, orgID, permissionID, ""); err != nil {
return err return err
} }
return nil return nil
@ -504,12 +554,12 @@ func (a *appAuth) Perm(permissionID string) func(*vigo.X) error {
func (a *appAuth) PermOnResource(permissionID, resourceKey string) func(*vigo.X) error { func (a *appAuth) PermOnResource(permissionID, resourceKey string) func(*vigo.X) error {
validatePermissionID(permissionID) validatePermissionID(permissionID)
return func(x *vigo.X) error { return func(x *vigo.X) error {
userID := GetUserID(x) userID := a.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
orgID := GetOrgID(x) orgID := a.OrgID(x)
// 尝试从 PathParams 获取 // 尝试从 PathParams 获取
resourceID := x.PathParams.Get(resourceKey) resourceID := x.PathParams.Get(resourceKey)
@ -542,11 +592,11 @@ func (a *appAuth) PermAny(permissionIDs ...string) func(*vigo.X) error {
validatePermissionID(pid) validatePermissionID(pid)
} }
return func(x *vigo.X) error { return func(x *vigo.X) error {
userID := GetUserID(x) userID := a.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
orgID := GetOrgID(x) orgID := a.OrgID(x)
for _, pid := range permissionIDs { for _, pid := range permissionIDs {
if err := a.checkPermission(x.Context(), userID, orgID, pid, ""); err == nil { if err := a.checkPermission(x.Context(), userID, orgID, pid, ""); err == nil {
@ -562,11 +612,11 @@ func (a *appAuth) PermAll(permissionIDs ...string) func(*vigo.X) error {
validatePermissionID(pid) validatePermissionID(pid)
} }
return func(x *vigo.X) error { return func(x *vigo.X) error {
userID := GetUserID(x) userID := a.UserID(x)
if userID == "" { if userID == "" {
return vigo.ErrUnauthorized return vigo.ErrUnauthorized
} }
orgID := GetOrgID(x) orgID := a.OrgID(x)
for _, pid := range permissionIDs { for _, pid := range permissionIDs {
if err := a.checkPermission(x.Context(), userID, orgID, pid, ""); err != nil { if err := a.checkPermission(x.Context(), userID, orgID, pid, ""); err != nil {
@ -634,6 +684,49 @@ func (a *appAuth) GrantRole(ctx context.Context, userID, orgID, roleCode string)
return nil return nil
} }
// GrantRoles 批量授予角色
func (a *appAuth) GrantRoles(ctx context.Context, userID, orgID string, roleCodes ...string) error {
for _, roleCode := range roleCodes {
if err := a.GrantRole(ctx, userID, orgID, roleCode); err != nil {
return err
}
}
return nil
}
// ListUserRoles 查询用户的角色列表
func (a *appAuth) ListUserRoles(ctx context.Context, userID, orgID string) ([]string, error) {
var roleIDs []string
query := cfg.DB().Model(&models.UserRole{}).
Where("user_id = ?", userID)
if orgID != "" {
query = query.Where("org_id = ? OR org_id IS NULL", orgID)
} else {
query = query.Where("org_id IS NULL")
}
if err := query.Pluck("role_id", &roleIDs).Error; err != nil {
return nil, err
}
if len(roleIDs) == 0 {
return []string{}, nil
}
// 获取角色代码
var roles []models.Role
if err := cfg.DB().Where("id IN ?", roleIDs).Pluck("code", &roles).Error; err != nil {
return nil, err
}
codes := make([]string, 0, len(roles))
for _, role := range roles {
codes = append(codes, role.Code)
}
return codes, nil
}
func (a *appAuth) RevokeRole(ctx context.Context, userID, orgID, roleCode string) error { func (a *appAuth) RevokeRole(ctx context.Context, userID, orgID, roleCode string) error {
var role models.Role var role models.Role
// 优先查找组织特定角色 // 优先查找组织特定角色
@ -669,6 +762,16 @@ func (a *appAuth) RevokeRole(ctx context.Context, userID, orgID, roleCode string
return nil return nil
} }
// RevokeRoles 批量撤销角色
func (a *appAuth) RevokeRoles(ctx context.Context, userID, orgID string, roleCodes ...string) error {
for _, roleCode := range roleCodes {
if err := a.RevokeRole(ctx, userID, orgID, roleCode); err != nil {
return err
}
}
return nil
}
func (a *appAuth) GrantResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error { func (a *appAuth) GrantResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error {
if strings.Count(permissionID, ":") == 1 { if strings.Count(permissionID, ":") == 1 {
permissionID = fmt.Sprintf("%s:%s", a.scope, permissionID) permissionID = fmt.Sprintf("%s:%s", a.scope, permissionID)
@ -855,8 +958,8 @@ func (a *appAuth) checkPermissionDB(ctx context.Context, userID, orgID, permissi
return userPermCount > 0, nil return userPermCount > 0, nil
} }
func (a *appAuth) ListUserPermissions(ctx context.Context, userID, orgID string) ([]models.UserPermissionResult, error) { func (a *appAuth) ListUserPermissions(ctx context.Context, userID, orgID string) ([]*vigoauth.UserPermission, error) {
result := make([]models.UserPermissionResult, 0) result := make([]*vigoauth.UserPermission, 0)
// 1. 获取用户角色对应的权限 // 1. 获取用户角色对应的权限
var roleIDs []string var roleIDs []string
@ -876,10 +979,15 @@ func (a *appAuth) ListUserPermissions(ctx context.Context, userID, orgID string)
} }
for _, permID := range permIDs { for _, permID := range permIDs {
result = append(result, models.UserPermissionResult{ parts := strings.Split(permID, ":")
PermissionID: permID, resource := "*"
ResourceID: "*", if len(parts) >= 2 {
Actions: []string{"*"}, resource = parts[len(parts)-2]
}
result = append(result, &vigoauth.UserPermission{
Resource: resource,
ResourceID: "*",
Actions: []string{"*"},
}) })
} }
} }
@ -893,18 +1001,23 @@ func (a *appAuth) ListUserPermissions(ctx context.Context, userID, orgID string)
} }
for _, up := range userPerms { for _, up := range userPerms {
result = append(result, models.UserPermissionResult{ parts := strings.Split(up.PermissionID, ":")
PermissionID: up.PermissionID, resource := "*"
ResourceID: up.ResourceID, if len(parts) >= 2 {
Actions: []string{"*"}, resource = parts[len(parts)-2]
}
result = append(result, &vigoauth.UserPermission{
Resource: resource,
ResourceID: up.ResourceID,
Actions: []string{"*"},
}) })
} }
return result, nil return result, nil
} }
func (a *appAuth) ListResourceUsers(ctx context.Context, orgID, permissionID, resourceID string) ([]models.ResourceUser, error) { func (a *appAuth) ListResourceUsers(ctx context.Context, orgID, permissionID, resourceID string) ([]*vigoauth.ResourceUser, error) {
result := make([]models.ResourceUser, 0) result := make([]*vigoauth.ResourceUser, 0)
// 查询有该资源权限的用户 // 查询有该资源权限的用户
var userPerms []models.UserPermission var userPerms []models.UserPermission
@ -923,7 +1036,7 @@ func (a *appAuth) ListResourceUsers(ctx context.Context, orgID, permissionID, re
} }
for userID, actions := range userMap { for userID, actions := range userMap {
result = append(result, models.ResourceUser{ result = append(result, &vigoauth.ResourceUser{
UserID: userID, UserID: userID,
Actions: actions, Actions: actions,
}) })

@ -1,58 +0,0 @@
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
package auth
import (
"strings"
"github.com/veypi/vbase/libs/cache"
"github.com/veypi/vbase/libs/jwt"
"github.com/veypi/vigo"
)
// AuthMiddleware 统一认证中间件
// 仅处理 JWT 认证,设置 CtxKeyUserID
// 组织信息的加载需按需调用 Auth.LoadOrg(x)
func AuthMiddleware() func(*vigo.X) error {
return func(x *vigo.X) error {
// === 1. JWT 认证部分 ===
tokenString := extractToken(x)
if tokenString == "" {
return vigo.ErrUnauthorized.WithString("missing token")
}
// 解析token
claims, err := jwt.ParseToken(tokenString)
if err != nil {
if err == jwt.ErrExpiredToken {
return vigo.ErrTokenExpired
}
return vigo.ErrTokenInvalid
}
// 检查token是否在黑名单中
if cache.IsEnabled() {
blacklisted, _ := cache.IsTokenBlacklisted(claims.ID)
if blacklisted {
return vigo.ErrUnauthorized.WithString("token has been revoked")
}
}
// 将用户信息存入上下文
x.Set(CtxKeyUserID, claims.UserID)
return nil
}
}
func extractToken(x *vigo.X) string {
auth := x.Request.Header.Get("Authorization")
if auth != "" {
if len(auth) > 7 && strings.HasPrefix(auth, "Bearer ") {
return auth[7:]
}
}
return x.Request.URL.Query().Get("access_token")
}

@ -75,3 +75,5 @@ var Global = &Options{
} }
var DB = Global.DB.Client var DB = Global.DB.Client
var Redis = Global.Redis.Client

@ -9,8 +9,11 @@ package main
import ( import (
"github.com/veypi/vbase" "github.com/veypi/vbase"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vigo"
) )
func main() { func main() {
panic(vbase.App.Run()) app := vigo.New("vbase", vbase.Router, cfg.Global, vbase.Init)
panic(app.Run())
} }

@ -19,12 +19,15 @@ import (
) )
var Router = vigo.NewRouter() var Router = vigo.NewRouter()
var ( var (
Auth = auth.Factory NewAuth = auth.Factory.New
AuthMiddleware = auth.AuthMiddleware Config = cfg.Global
) )
func Init() error {
return models.Migrate()
}
//go:embed ui //go:embed ui
var uifs embed.FS var uifs embed.FS
@ -34,9 +37,3 @@ func init() {
Router.Extend("vhtml", vhtml.Router) Router.Extend("vhtml", vhtml.Router)
vhtml.WrapUI(Router, uifs) vhtml.WrapUI(Router, uifs)
} }
var App = vigo.New("vbase", Router, cfg.Global, Init)
func Init() error {
return models.Migrate()
}

Loading…
Cancel
Save