Files
zzyxyz_go_api/internal/vfs/vfs_auth.go
zzy b2cc27b8f5 refactor(bookmark): 重构 bookmark 服务生成配置和内部引用
将 bookmark 和 user_np 服务的生成配置分离为 server 和 client 包,
并更新了相应的导入路径。同时更新了 OpenAPI 配置文件中的包名、输出路径及
启用 strict-server 模式以增强类型安全。

此外,同步更新了 VFS 服务的客户端和服务端生成配置,并完善了其 OpenAPI
错误响应定义与二进制内容支持,增强了 API 的规范性和健壮性。

修复了部分权限校验逻辑,并调整了中间件注册方式以适配新的严格模式接口。
2025-09-25 16:15:34 +08:00

190 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package vfs
import (
_ "embed"
"strings"
api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/vfs_server"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/vfs/models"
"github.com/gin-gonic/gin"
)
//go:embed vfs_model.conf
var CasbinModel string
// 使用示例在main.go或路由注册处
func RegisterVFSRoutes(router gin.IRouter, vfsHandler *VfsImpl) {
// 创建严格模式handler并添加权限中间件
strictHandler := api.NewStrictHandler(vfsHandler, []api.StrictMiddlewareFunc{
vfsHandler.PermissionMiddleware,
})
// 注册handler
api.RegisterHandlers(router, strictHandler)
}
// PermissionMiddleware 是一个权限验证中间件
func (v *VfsImpl) PermissionMiddleware(handler api.StrictHandlerFunc, operation string) api.StrictHandlerFunc {
return func(ctx *gin.Context, request interface{}) (interface{}, error) {
// 从请求头获取token
token := ctx.GetHeader("X-VFS-Token")
// Admin token 拥有所有权限
if token == v.config.AdminToken && len(token) != 0 {
return handler(ctx, request)
}
// 根据操作类型进行不同的权限检查
switch operation {
case "CreateUser":
// 只有admin或register token可以创建用户
if token != v.config.RegisterToken {
return api.CreateUser403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
}
return handler(ctx, request)
// 如果是删除用户操作,检查是否具有管理员权限
case "DeleteUser":
// 获取要删除的用户名
var username string
if req, ok := request.(api.DeleteUserRequestObject); ok {
username = req.Username
}
// 验证token对应的用户是否存在
user, err := v.vfs.GetUserByToken(token)
if err != nil || (user.Name != username && token != v.config.AdminToken) {
return api.DeleteUser403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
}
// 如果验证通过,继续执行原处理函数
return handler(ctx, request)
case "GetVFSNode", "CreateVFSNode", "UpdateVFSNode", "DeleteVFSNode":
// VFS节点操作的权限检查
var path string
var method string
// 根据操作类型获取路径和HTTP方法
switch operation {
case "GetVFSNode":
if req, ok := request.(api.GetVFSNodeRequestObject); ok {
path = req.Params.Path
}
method = "GET"
case "CreateVFSNode":
if req, ok := request.(api.CreateVFSNodeRequestObject); ok {
path = req.Params.Path
}
method = "POST"
case "UpdateVFSNode":
if req, ok := request.(api.UpdateVFSNodeRequestObject); ok {
path = req.Params.Path
}
method = "PATCH"
case "DeleteVFSNode":
if req, ok := request.(api.DeleteVFSNodeRequestObject); ok {
path = req.Params.Path
}
method = "DELETE"
}
// 检查权限
allowed, err := v.CheckPermission(token, path, method)
if err != nil {
return api.GetVFSNode500JSONResponse{
ServerInternalErrorJSONResponse: api.ServerInternalErrorJSONResponse{
Errtype: api.ErrorErrtypeInternalServerError,
Message: "Failed to check permission: " + err.Error(),
},
}, nil
}
if !allowed {
// 根据操作类型返回相应的错误响应
switch operation {
case "GetVFSNode":
return api.GetVFSNode403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
case "CreateVFSNode":
return api.CreateVFSNode403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
case "UpdateVFSNode":
return api.UpdateVFSNode403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
case "DeleteVFSNode":
return api.DeleteVFSNode403JSONResponse{
ForbiddenErrorJSONResponse: api.ForbiddenErrorJSONResponse{
Errtype: api.ErrorErrtypeForbidden,
Message: "Access denied",
},
}, nil
}
}
return handler(ctx, request)
default:
return api.Error{
Errtype: api.ErrorErrtypeForbidden,
Message: "not supported function it's a bug in backend",
}, nil
}
}
}
// CheckPermission 检查用户对指定路径的权限
// FIXME: using casbin to check it
func (v *VfsImpl) CheckPermission(token, path, method string) (bool, error) {
// Admin token 拥有所有权限
if token == v.config.AdminToken && len(token) != 0 {
return true, nil
}
// 根据 token 获取用户信息
user, err := v.vfs.GetUserByToken(token)
if err != nil {
// 匿名用户
user = &models.VfsUser{Name: "", Token: ""}
}
// 允许任何人读取 public 目录
if method == "GET" && strings.HasPrefix(path, "/public") {
return true, nil
}
// 如果是普通用户访问自己的主目录,则允许
if user.Name != "" && strings.HasPrefix(path, "/home/"+user.Name) {
return true, nil
}
// 使用 Casbin 检查权限
// sub: 用户名 (匿名用户为空字符串)
// obj: 路径
// act: HTTP方法
allowed, err := v.enfocer.Enforce(user.Name, path, method)
if err != nil {
return false, err
}
return allowed, nil
}