feat(middleware): add AdminRequired authorization middleware
AdminRequired gates admin endpoints by checking user IsAdmin flag. Placed AFTER AuthRequired; fetches user from repository, returns 403 for non-admins. Soft-deleted users are rejected with 401 since FindByID excludes them. Tests: admin passes, non-admin forbidden, soft-deleted admin rejected, missing user ID. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/dhao2001/mygo/internal/api"
|
||||
"github.com/dhao2001/mygo/internal/auth"
|
||||
"github.com/dhao2001/mygo/internal/repository"
|
||||
)
|
||||
|
||||
const userIDKey = "user_id"
|
||||
@@ -68,3 +69,33 @@ func MustGetUserID(c *gin.Context) string {
|
||||
}
|
||||
return userID
|
||||
}
|
||||
|
||||
// AdminRequired returns a Gin middleware that gates access to admin-only
|
||||
// endpoints. It must be applied AFTER AuthRequired. It fetches the user from
|
||||
// the repository, and returns 403 if the user is not an admin. Soft-deleted
|
||||
// users are not found by FindByID and will receive a 401 response.
|
||||
func AdminRequired(userRepo repository.UserRepository) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
userID := GetUserID(c)
|
||||
if userID == "" {
|
||||
api.Error(c, http.StatusUnauthorized, "missing user context")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
user, err := userRepo.FindByID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
api.Error(c, http.StatusUnauthorized, "user not found")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !user.IsAdmin {
|
||||
api.Error(c, http.StatusForbidden, "admin access required")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user