Merge pull request #1258 from trheyi/main

Add authorization checks and filtering in collection and document lis…
This commit is contained in:
Max 2025-10-31 19:51:14 +08:00 committed by GitHub
commit 4409133837
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 89 additions and 3 deletions

View file

@ -309,6 +309,10 @@ func GetCollection(c *gin.Context) {
// ListCollections lists collections with pagination
func ListCollections(c *gin.Context) {
// Get authorized information
authInfo := authorized.GetInfo(c)
// Check if kb.Instance is available
if kb.Instance == nil {
errorResp := &response.ErrorResponse{
@ -364,13 +368,14 @@ func ListCollections(c *gin.Context) {
}
// Build query parameters
param := model.QueryParam{
Select: selectFields,
}
param := model.QueryParam{Select: selectFields}
// Add filters
var wheres []model.QueryWhere
// Apply permission-based filtering
wheres = append(wheres, AuthFilter(c, authInfo)...)
// Filter by keywords (search in name and description)
if keywords := strings.TrimSpace(c.Query("keywords")); keywords != "" {
wheres = append(wheres, model.QueryWhere{

View file

@ -10,6 +10,7 @@ import (
"github.com/yaoapp/gou/model"
"github.com/yaoapp/yao/attachment"
"github.com/yaoapp/yao/kb"
"github.com/yaoapp/yao/openapi/oauth/authorized"
"github.com/yaoapp/yao/openapi/response"
)
@ -102,9 +103,15 @@ func ListDocuments(c *gin.Context) {
Select: selectFields,
}
// Get authorized information
authInfo := authorized.GetInfo(c)
// Add filters
var wheres []model.QueryWhere
// Apply permission-based filtering
wheres = append(wheres, AuthFilter(c, authInfo)...)
// Filter by keywords (search in name and description)
if keywords := strings.TrimSpace(c.Query("keywords")); keywords != "" {
wheres = append(wheres, model.QueryWhere{

68
openapi/kb/filter.go Normal file
View file

@ -0,0 +1,68 @@
package kb
import (
"github.com/gin-gonic/gin"
"github.com/yaoapp/gou/model"
"github.com/yaoapp/yao/openapi/oauth/authorized"
"github.com/yaoapp/yao/openapi/oauth/types"
)
// AuthFilter applies permission-based filtering to query wheres
// This function builds where clauses based on the user's authorization constraints
// It supports TeamOnly and OwnerOnly constraints for data access control
//
// Parameters:
// - c: gin.Context containing authorization information
// - authInfo: authorized information extracted from the context
//
// Returns:
// - []model.QueryWhere: array of where clauses to apply to the query
func AuthFilter(c *gin.Context, authInfo *types.AuthorizedInfo) []model.QueryWhere {
if authInfo == nil {
return []model.QueryWhere{}
}
var wheres []model.QueryWhere
scope := authInfo.AccessScope()
// Team only - User can access:
// 1. Public records (public = true)
// 2. Records in their team where:
// - They created the record (__yao_created_by matches)
// - OR the record is shared with team (share = "team")
if authInfo.Constraints.TeamOnly && authorized.IsTeamMember(c) {
wheres = append(wheres, model.QueryWhere{
Wheres: []model.QueryWhere{
{Column: "public", Value: true, Method: "orwhere"},
{Wheres: []model.QueryWhere{
{Column: "__yao_team_id", Value: scope.TeamID},
{Wheres: []model.QueryWhere{
{Column: "__yao_created_by", Value: scope.CreatedBy},
{Column: "share", Value: "team", Method: "orwhere"},
}},
}, Method: "orwhere"},
},
})
return wheres
}
// Owner only - User can access:
// 1. Public records (public = true)
// 2. Records they created where:
// - __yao_team_id is null (not team records)
// - __yao_created_by matches their user ID
if authInfo.Constraints.OwnerOnly && authInfo.UserID != "" {
wheres = append(wheres, model.QueryWhere{
Wheres: []model.QueryWhere{
{Column: "public", Value: true, Method: "orwhere"},
{Wheres: []model.QueryWhere{
{Column: "__yao_team_id", OP: "null"},
{Column: "__yao_created_by", Value: scope.CreatedBy},
}, Method: "orwhere"},
},
})
return wheres
}
return wheres
}

View file

@ -50,6 +50,12 @@ func GetInfo(c *gin.Context) *types.AuthorizedInfo {
return info
}
// IsTeamMember checks if the user is a team member
func IsTeamMember(c *gin.Context) bool {
authInfo := GetInfo(c)
return authInfo != nil && authInfo.TeamID != "" && authInfo.UserID != ""
}
// GetConstraints extracts data access constraints from the gin context
// Returns a DataConstraints struct with all constraint flags
func GetConstraints(c *gin.Context) types.DataConstraints {