5.3 认证与授权
Session/Cookie 认证
go
import (
"github.com/gorilla/sessions"
)
var store = sessions.NewCookieStore([]byte("secret-key"))
r.POST("/login", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
if username != "admin" || password != "password" {
c.JSON(401, gin.H{"error": "用户名或密码错误"})
return
}
session, _ := store.Get(c.Request, "session")
session.Options = &sessions.Options{
Path: "/",
MaxAge: 86400,
}
session.Values["username"] = username
session.Save(c.Request, c.Writer)
c.JSON(200, gin.H{"message": "登录成功"})
})
r.GET("/logout", func(c *gin.Context) {
session, _ := store.Get(c.Request, "session")
session.Options.MaxAge = -1
session.Save(c.Request, c.Writer)
})JWT Token 认证
go
import "github.com/golang-jwt/jwt/v5"
var jwtKey = []byte("secret-key")
type Claims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims
}
// 登录生成 Token
func loginHandler(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
if username != "admin" || password != "password" {
c.JSON(401, gin.H{"error": "用户名或密码错误"})
return
}
claims := Claims{
UserID: 1,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, _ := token.SignedString(jwtKey)
c.JSON(200, gin.H{"token": tokenString})
}
// JWT 认证中间件
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil || !token.Valid {
c.AbortWithStatusJSON(401, gin.H{"error": "token 无效"})
return
}
c.Set("userID", claims.UserID)
c.Next()
}
}OAuth2.0 集成
go
import "golang.org/x/oauth2"
var oauthConfig = &oauth2.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
RedirectURL: "http://localhost:8080/auth/callback",
Scopes: []string{"read:user"},
Endpoint: github.Endpoint,
}
r.GET("/auth/login", func(c *gin.Context) {
url := oauthConfig.AuthCodeURL("state", oauth2.AccessTypeOffline)
c.Redirect(http.StatusTemporaryRedirect, url)
})
r.GET("/auth/callback", func(c *gin.Context) {
code := c.Query("code")
token, _ := oauthConfig.Exchange(context.Background(), code)
client := oauthConfig.Client(context.Background(), token)
resp, _ := client.Get("https://api.github.com/user")
defer resp.Body.Close()
var user map[string]interface{}
json.NewDecoder(resp.Body).Decode(&user)
c.JSON(200, gin.H{"user": user})
})RBAC 权限模型
go
type Role string
type Permission string
const (
RoleAdmin Role = "admin"
RoleEditor Role = "editor"
RoleViewer Role = "viewer"
PermRead Permission = "read"
PermWrite Permission = "write"
PermDelete Permission = "delete"
)
var rolePermissions = map[Role][]Permission{
RoleAdmin: {PermRead, PermWrite, PermDelete},
RoleEditor: {PermRead, PermWrite},
RoleViewer: {PermRead},
}
func RequirePermission(requiredPerm Permission) gin.HandlerFunc {
return func(c *gin.Context) {
role, _ := c.Get("role")
perms := rolePermissions[Role(role.(string))]
hasPermission := false
for _, p := range perms {
if p == requiredPerm {
hasPermission = true
break
}
}
if !hasPermission {
c.AbortWithStatusJSON(403, gin.H{"error": "权限不足"})
return
}
c.Next()
}
}Casbin
go
import "github.com/casbin/casbin/v2"
// model.conf
/*
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
*/
enforcer, _ := casbin.NewEnforcer("model.conf", "policy.csv")
r.Use(func(c *gin.Context) {
user := c.GetHeader("X-User")
obj := c.Request.URL.Path
act := c.Request.Method
allowed, _ := enforcer.Enforce(user, obj, act)
if !allowed {
c.AbortWithStatusJSON(403, gin.H{"error": "权限不足"})
return
}
c.Next()
})