Skip to content

5.3 认证与授权 ​

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()
})