Golang中私有与公有端点的实现与区别
Golang中私有与公有端点的实现与区别 假设我们有两个用于获取产品信息的端点。 在这些产品信息中,包含产品的名称和价格。
第一个端点供已认证用户使用,可以访问产品的名称和价格。
第二个端点是公开的,只能访问产品的名称。
在这种情况下,最佳的模式是什么:
是分别创建私有处理函数和公共处理函数吗?如果是,那么如果我需要为每个用户角色(公开、私有、管理员…)提供不同的访问权限,是否应该创建与用户范围一样多的端点?
还是使用相同的处理函数,并添加一个类似 IsPublic 的参数?
我找不到相关的关键词来阅读这方面的内容。
您的授权函数可以返回一个描述允许访问字段的策略,视图生成函数则可以使用该属性列表来构建视图。不过,这会使您的视图函数变得复杂得多。我认为,我可能会在视图函数中根据用户的状态进行分支判断。这样,授权逻辑目前可以保持简单,代价是声明性会差一些。
我还没有研究过 oso,但它可能也提供了一些与此相关的指导。
更多关于Golang中私有与公有端点的实现与区别的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
好的,没问题。
我完全同意在中间件中加入授权和认证。 但是,如果我们有第三个字段,包含所有已售出产品的历史记录,该怎么办?
我想为管理员提供所有已售出产品的历史记录访问权限,而公开只提供最近一个月的历史记录。
我应该为两者使用同一个函数并加上一个布尔参数(如 isPublic),还是应该创建单独的函数?
我的意思是,哪种方式更好?
我不是这方面的专家,但我的第一反应是为所有访问级别创建一个路由,并设置两层服务。外层服务将接收某种身份验证令牌,将其解析为用户ID,然后向另一个HTTP服务发起请求,并在HTTP头部中携带该用户ID。
一旦你有了用户ID,就可以创建一些库函数,这些函数引用一个持久化的用户到其访问级别的映射。每个端点都会查找用户的访问级别,然后根据访问级别生成相应的请求。
关于授权实现相关的关键词,你可以阅读关于不同授权方法的内容,例如RBAC。
在Go中实现私有与公有端点,通常建议使用中间件进行权限控制,而不是创建多个处理函数。以下是一个示例实现:
package main
import (
"encoding/json"
"net/http"
)
// 产品结构体
type Product struct {
Name string `json:"name"`
Price float64 `json:"price,omitempty"` // omitempty会在序列化时根据条件省略
}
// 中间件:检查访问权限
func authMiddleware(next http.HandlerFunc, isPublic bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if isPublic {
// 公开端点:直接调用处理函数
next(w, r)
return
}
// 私有端点:检查认证
token := r.Header.Get("Authorization")
if token == "" || !isValidToken(token) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next(w, r)
}
}
// 统一的处理函数
func getProductHandler(w http.ResponseWriter, r *http.Request, showPrice bool) {
product := Product{
Name: "示例产品",
Price: 99.99,
}
// 根据权限决定是否显示价格
if !showPrice {
product.Price = 0 // 设置为零值,omitempty会忽略
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(product)
}
// 包装为公开端点
func publicProductHandler(w http.ResponseWriter, r *http.Request) {
getProductHandler(w, r, false)
}
// 包装为私有端点
func privateProductHandler(w http.ResponseWriter, r *http.Request) {
getProductHandler(w, r, true)
}
// 辅助函数:验证token
func isValidToken(token string) bool {
// 实现实际的token验证逻辑
return token == "valid-token"
}
func main() {
// 注册路由,应用中间件
http.HandleFunc("/api/product/public",
authMiddleware(publicProductHandler, true))
http.HandleFunc("/api/product/private",
authMiddleware(privateProductHandler, false))
http.ListenAndServe(":8080", nil)
}
对于多角色权限控制,可以使用基于角色的访问控制(RBAC)模式:
// 角色定义
type Role string
const (
RolePublic Role = "public"
RoleUser Role = "user"
RoleAdmin Role = "admin"
)
// 带角色的中间件
func roleBasedMiddleware(allowedRoles []Role) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userRole := getUserRoleFromRequest(r)
// 检查用户角色是否在允许的列表中
allowed := false
for _, role := range allowedRoles {
if userRole == role {
allowed = true
break
}
}
if !allowed {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next(w, r)
}
}
}
// 统一的产品处理函数
func productHandler(w http.ResponseWriter, r *http.Request) {
userRole := getUserRoleFromRequest(r)
product := Product{
Name: "示例产品",
Price: 99.99,
}
// 根据角色决定返回的数据
switch userRole {
case RolePublic:
product.Price = 0
case RoleUser:
// 显示价格
case RoleAdmin:
product.Price = 99.99
// 管理员可以看到额外字段
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(product)
}
// 路由注册示例
func setupRoutes() {
// 同一个端点,不同角色访问不同数据
http.HandleFunc("/api/product",
roleBasedMiddleware([]Role{RolePublic, RoleUser, RoleAdmin})(productHandler))
// 或者为不同角色创建不同端点
http.HandleFunc("/api/product/public",
roleBasedMiddleware([]Role{RolePublic})(productHandler))
http.HandleFunc("/api/product/user",
roleBasedMiddleware([]Role{RoleUser, RoleAdmin})(productHandler))
}
这种模式的优点:
- 保持代码DRY(Don’t Repeat Yourself)
- 权限逻辑集中管理
- 易于扩展新的角色
- 端点结构清晰
实际项目中,可以考虑使用现有的权限库如casbin或go-guardian来简化实现。

