Golang中如何创建访问级别列表
Golang中如何创建访问级别列表 大家好,
我正在尝试用Go语言创建一个市场平台,目前源代码已发布在GitHub上:https://github.com/mehrdaddolatkhah/market-place
在这个服务中,我设置了三种角色:管理员、用户和营销人员。
现在我想为这个服务创建一个访问级别列表。我应该怎么做呢?
我目前的策略是在REST包中创建一个中间层,然后检查JWT令牌。我在JWT令牌中存放了用户ID,接着检查用户调用的端点,然后根据该角色查询数据库。如果用户存在并且有权访问该端点的数据,则返回响应。这是一个好的解决方案吗?或者大家通常是如何处理这个问题的?
感谢您的建议。
抱歉我的英语不好。我正在学术环境中开始学习英语,需要一些时间才能变得更好。
更多关于Golang中如何创建访问级别列表的实战教程也可以访问 https://www.itying.com/category-94-b0.html
有些人在 Slack Gophers 频道向我推荐了这个库:https://github.com/casbin/casbin 但我不想使用这个库,我在寻找一种方法,人们如何在服务中为不同角色处理访问权限,并且具备一定的安全性。我不希望用户能够访问管理员部分,或者任何其他角色访问与他们无关的某些部分。你们在服务中是如何处理角色之间的这种访问权限的?
更多关于Golang中如何创建访问级别列表的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我猜您正在开发某种Web应用程序。对于需要角色和访问权限的应用,我使用了Gorilla mux,配合子路由并在中间件中实现身份验证。
在Go中实现访问控制列表(ACL)通常采用中间件结合角色/权限验证的方式。以下是针对您场景的具体实现方案:
1. 定义角色和权限常量
// auth/roles.go
package auth
type Role string
const (
RoleAdmin Role = "admin"
RoleUser Role = "user"
RoleMarketer Role = "marketer"
)
// 权限定义
type Permission string
const (
PermissionCreateProduct Permission = "product:create"
PermissionDeleteProduct Permission = "product:delete"
PermissionViewAnalytics Permission = "analytics:view"
PermissionManageUsers Permission = "users:manage"
)
// 角色权限映射
var RolePermissions = map[Role][]Permission{
RoleAdmin: {
PermissionCreateProduct,
PermissionDeleteProduct,
PermissionViewAnalytics,
PermissionManageUsers,
},
RoleUser: {
PermissionCreateProduct,
},
RoleMarketer: {
PermissionCreateProduct,
PermissionViewAnalytics,
},
}
2. 实现JWT中间件
// middleware/auth.go
package middleware
import (
"context"
"net/http"
"strings"
"your-project/auth"
"your-project/models"
)
type contextKey string
const UserContextKey contextKey = "user"
func AuthMiddleware(jwtSecret string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, "Authorization header required", http.StatusUnauthorized)
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
claims, err := auth.ValidateToken(tokenString, jwtSecret)
if err != nil {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
// 将用户信息存入上下文
user := &models.User{
ID: claims.UserID,
Role: auth.Role(claims.Role),
Email: claims.Email,
}
ctx := context.WithValue(r.Context(), UserContextKey, user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
3. 实现ACL中间件
// middleware/acl.go
package middleware
import (
"net/http"
"your-project/auth"
)
func RequirePermission(permission auth.Permission) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, ok := r.Context().Value(UserContextKey).(*models.User)
if !ok {
http.Error(w, "User not found in context", http.StatusUnauthorized)
return
}
// 检查用户角色是否拥有所需权限
permissions, exists := auth.RolePermissions[user.Role]
if !exists {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
hasPermission := false
for _, p := range permissions {
if p == permission {
hasPermission = true
break
}
}
if !hasPermission {
http.Error(w, "Insufficient permissions", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}
// 基于角色的快捷方式
func RequireRole(role auth.Role) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, ok := r.Context().Value(UserContextKey).(*models.User)
if !ok {
http.Error(w, "User not found in context", http.StatusUnauthorized)
return
}
if user.Role != role {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}
4. 路由配置示例
// routes/routes.go
package routes
import (
"net/http"
"your-project/handlers"
"your-project/middleware"
"your-project/auth"
)
func SetupRoutes() http.Handler {
mux := http.NewServeMux()
// 公开路由
mux.HandleFunc("/login", handlers.LoginHandler)
mux.HandleFunc("/register", handlers.RegisterHandler)
// 需要认证的路由
authMiddleware := middleware.AuthMiddleware("your-jwt-secret")
// 用户路由
mux.Handle("/products", authMiddleware(
middleware.RequirePermission(auth.PermissionCreateProduct)(
http.HandlerFunc(handlers.CreateProductHandler),
),
))
// 管理员路由
mux.Handle("/admin/users", authMiddleware(
middleware.RequireRole(auth.RoleAdmin)(
http.HandlerFunc(handlers.ManageUsersHandler),
),
))
// 营销人员路由
mux.Handle("/analytics", authMiddleware(
middleware.RequirePermission(auth.PermissionViewAnalytics)(
http.HandlerFunc(handlers.ViewAnalyticsHandler),
),
))
return mux
}
5. JWT令牌生成和验证
// auth/jwt.go
package auth
import (
"time"
"github.com/golang-jwt/jwt/v4"
)
type Claims struct {
UserID string `json:"user_id"`
Role string `json:"role"`
Email string `json:"email"`
jwt.RegisteredClaims
}
func GenerateToken(userID, role, email, secret string) (string, error) {
claims := Claims{
UserID: userID,
Role: role,
Email: email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secret))
}
func ValidateToken(tokenString, secret string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, jwt.ErrSignatureInvalid
}
6. 数据库查询优化
// repository/user_repo.go
package repository
import (
"context"
"database/sql"
"your-project/models"
)
type UserRepository struct {
db *sql.DB
}
func (r *UserRepository) GetUserWithPermissions(ctx context.Context, userID string) (*models.UserWithPermissions, error) {
query := `
SELECT u.id, u.email, u.role,
ARRAY_AGG(p.permission) as permissions
FROM users u
LEFT JOIN role_permissions rp ON u.role = rp.role
LEFT JOIN permissions p ON rp.permission_id = p.id
WHERE u.id = $1
GROUP BY u.id, u.email, u.role
`
var user models.UserWithPermissions
err := r.db.QueryRowContext(ctx, query, userID).Scan(
&user.ID,
&user.Email,
&user.Role,
&user.Permissions,
)
if err != nil {
return nil, err
}
return &user, nil
}
这个方案将访问控制逻辑从业务代码中分离出来,通过中间件实现权限验证。JWT中存储用户角色,中间件根据路由需要的权限进行验证,避免了每次请求都查询数据库。对于更复杂的权限系统,可以考虑使用Casbin等成熟的ACL库。

