认证与授权
基本认证
实现基本的用户名密码认证。
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")
}
}