认证与授权

基本认证

实现基本的用户名密码认证。

package main

import (
    "crypto/subtle"
    "net/http"
)

type User struct {
    Username string
    Password string
}

var users = map[string]string{
    "admin": "password123",
}

func basicAuth(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        username, password, ok := r.BasicAuth()
        if !ok {
            w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        expectedPassword, exists := users[username]
        if !exists || subtle.ConstantTimeCompare([]byte(password), []byte(expectedPassword)) != 1 {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        next.ServeHTTP(w, r)
    }
}

func main() {
    http.HandleFunc("/", basicAuth(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Welcome to the protected area!"))
    }))
    
    http.ListenAndServe(":8080", nil)
}

JWT认证

使用JWT实现无状态认证。

package main

import (
    "net/http"
    "time"
    "github.com/dgrijalva/jwt-go"
)

type Claims struct {
    Username string `json:"username"`
    Role     string `json:"role"`
    jwt.StandardClaims
}

var jwtKey = []byte("your-secret-key")

func generateToken(username, role string) (string, error) {
    expirationTime := time.Now().Add(24 * time.Hour)
    claims := &Claims{
        Username: username,
        Role:     role,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expirationTime.Unix(),
        },
    }
    
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(jwtKey)
}

func jwtMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tokenString := r.Header.Get("Authorization")
        if tokenString == "" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        claims := &Claims{}
        token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
            return jwtKey, nil
        })
        
        if err != nil || !token.Valid {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        next.ServeHTTP(w, r)
    }
}

func main() {
    http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
        // 处理登录...
        token, _ := generateToken("admin", "admin")
        w.Write([]byte(token))
    })
    
    http.HandleFunc("/protected", jwtMiddleware(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Protected resource"))
    }))
    
    http.ListenAndServe(":8080", nil)
}

OAuth2认证

实现OAuth2认证流程。

package main

import (
    "encoding/json"
    "net/http"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
)

var (
    oauthConfig = &oauth2.Config{
        ClientID:     "your-client-id",
        ClientSecret: "your-client-secret",
        RedirectURL:  "http://localhost:8080/callback",
        Scopes: []string{
            "https://www.googleapis.com/auth/userinfo.email",
            "https://www.googleapis.com/auth/userinfo.profile",
        },
        Endpoint: google.Endpoint,
    }
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        url := oauthConfig.AuthCodeURL("state")
        http.Redirect(w, r, url, http.StatusTemporaryRedirect)
    })
    
    http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
        code := r.URL.Query().Get("code")
        token, err := oauthConfig.Exchange(r.Context(), code)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        
        client := oauthConfig.Client(r.Context(), token)
        resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        defer resp.Body.Close()
        
        var userInfo map[string]interface{}
        if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        
        w.Write([]byte("Welcome " + userInfo["name"].(string)))
    })
    
    http.ListenAndServe(":8080", nil)
}

基于角色的访问控制

实现基于角色的访问控制(RBAC)。

package main

import (
    "net/http"
    "strings"
)

type Role struct {
    Name        string
    Permissions []string
}

var roles = map[string]Role{
    "admin": {
        Name: "admin",
        Permissions: []string{
            "read:users",
            "write:users",
            "delete:users",
        },
    },
    "user": {
        Name: "user",
        Permissions: []string{
            "read:users",
        },
    },
}

func hasPermission(role Role, permission string) bool {
    for _, p := range role.Permissions {
        if p == permission {
            return true
        }
    }
    return false
}

func rbacMiddleware(permission string) func(http.HandlerFunc) http.HandlerFunc {
    return func(next http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            roleName := r.Header.Get("X-User-Role")
            role, exists := roles[roleName]
            if !exists || !hasPermission(role, permission) {
                http.Error(w, "Forbidden", http.StatusForbidden)
                return
            }
            
            next.ServeHTTP(w, r)
        }
    }
}

func main() {
    http.HandleFunc("/users", rbacMiddleware("read:users")(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("List of users"))
    }))
    
    http.HandleFunc("/users/create", rbacMiddleware("write:users")(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Create user"))
    }))
    
    http.HandleFunc("/users/delete", rbacMiddleware("delete:users")(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Delete user"))
    }))
    
    http.ListenAndServe(":8080", nil)
}

密码加密

安全地存储和验证密码。

package main

import (
    "golang.org/x/crypto/bcrypt"
)

type User struct {
    Username string
    Password string
}

func hashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
    return string(bytes), err
}

func checkPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

func main() {
    password := "password123"
    hash, _ := hashPassword(password)
    
    // 验证密码
    match := checkPasswordHash(password, hash)
    if match {
        println("Password is correct")
    } else {
        println("Password is incorrect")
    }
}