将原先的 `vfs.go` 文件中的功能进行拆分,创建了独立的 DAO 层文件 `vfs_dao.go` 和路径处理文件 `vfs_path.go`,以提升代码结构清晰度和可维护性。 - 将数据库操作相关方法迁移至 `VfsDAO` 结构体中 - 新增 `vfs_dao.go` 文件用于管理底层数据访问对象 - 新增 `vfs_path.go` 文件专门处理路径解析逻辑 - 移除了原 `vfs.go` 中的数据库初始化、用户及节点操作等冗余代码
190 lines
5.4 KiB
Go
190 lines
5.4 KiB
Go
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.DAO.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.DAO.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
|
||
}
|