Golang中创建用户登录功能的实现
Golang中创建用户登录功能的实现 能否请您帮助我使用会话和数据库创建用户登录、登出、注册和权限功能。
3 回复
以下是使用Golang实现用户登录、注册、登出和权限管理功能的完整示例。我们将使用Gin框架作为HTTP路由器,GORM作为ORM工具,以及JWT(JSON Web Tokens)来处理会话管理。数据库使用SQLite,但你可以轻松替换为MySQL或PostgreSQL。
1. 项目结构和依赖
首先,创建项目结构并安装必要的依赖:
go mod init auth-example
go get github.com/gin-gonic/gin
go get gorm.io/gorm
go get gorm.io/driver/sqlite
go get github.com/golang-jwt/jwt/v4
go get golang.org/x/crypto/bcrypt
2. 数据库模型定义
在models/user.go中定义用户模型:
package models
import (
"gorm.io/gorm"
"golang.org/x/crypto/bcrypt"
)
type User struct {
gorm.Model
Username string `gorm:"uniqueIndex;not null" json:"username"`
Password string `gorm:"not null" json:"-"`
Role string `gorm:"default:user" json:"role"` // 权限角色:user, admin
}
// HashPassword 对密码进行哈希处理
func (u *User) HashPassword() error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
u.Password = string(hashedPassword)
return nil
}
// CheckPassword 验证密码
func (u *User) CheckPassword(password string) error {
return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
}
3. 数据库初始化
在database/database.go中初始化数据库:
package database
import (
"auth-example/models"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
var DB *gorm.DB
func InitDatabase() error {
var err error
DB, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
return err
}
// 自动迁移模型
err = DB.AutoMigrate(&models.User{})
if err != nil {
return err
}
return nil
}
4. JWT工具函数
在utils/jwt.go中处理JWT的生成和验证:
package utils
import (
"time"
"github.com/golang-jwt/jwt/v4"
)
var jwtSecret = []byte("your-secret-key") // 在生产环境中使用环境变量
type Claims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func GenerateToken(userID uint, username, role string) (string, error) {
expirationTime := time.Now().Add(24 * time.Hour)
claims := &Claims{
UserID: userID,
Username: username,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func ValidateToken(tokenString string) (*Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, jwt.ErrSignatureInvalid
}
return claims, nil
}
5. 中间件
在middleware/auth.go中创建认证和授权中间件:
package middleware
import (
"auth-example/utils"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
claims, err := utils.ValidateToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
c.Set("userID", claims.UserID)
c.Set("username", claims.Username)
c.Set("role", claims.Role)
c.Next()
}
}
func RoleMiddleware(allowedRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
userRole, exists := c.Get("role")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User role not found"})
c.Abort()
return
}
roleStr := userRole.(string)
for _, role := range allowedRoles {
if roleStr == role {
c.Next()
return
}
}
c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"})
c.Abort()
}
}
6. 路由和处理函数
在main.go中定义路由和处理函数:
package main
import (
"auth-example/database"
"auth-example/middleware"
"auth-example/models"
"auth-example/utils"
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func main() {
// 初始化数据库
if err := database.InitDatabase(); err != nil {
panic("Failed to connect to database: " + err.Error())
}
r := gin.Default()
// 注册路由
r.POST("/register", register)
r.POST("/login", login)
// 需要认证的路由组
auth := r.Group("/")
auth.Use(middleware.AuthMiddleware())
{
auth.GET("/profile", profile)
auth.POST("/logout", logout)
// 需要管理员权限的路由
admin := auth.Group("/admin")
admin.Use(middleware.RoleMiddleware("admin"))
{
admin.GET("/users", getUsers)
}
}
r.Run(":8080")
}
// 注册处理函数
func register(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 哈希密码
if err := user.HashPassword(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not hash password"})
return
}
// 保存用户到数据库
result := database.DB.Create(&user)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create user"})
return
}
c.JSON(http.StatusCreated, gin.H{
"message": "User created successfully",
"user": gin.H{
"id": user.ID,
"username": user.Username,
"role": user.Role,
},
})
}
// 登录处理函数
func login(c *gin.Context) {
var loginData struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&loginData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user models.User
result := database.DB.Where("username = ?", loginData.Username).First(&user)
if result.Error != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
return
}
// 验证密码
if err := user.CheckPassword(loginData.Password); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
return
}
// 生成JWT令牌
token, err := utils.GenerateToken(user.ID, user.Username, user.Role)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Login successful",
"token": token,
"user": gin.H{
"id": user.ID,
"username": user.Username,
"role": user.Role,
},
})
}
// 用户信息处理函数
func profile(c *gin.Context) {
userID, _ := c.Get("userID")
username, _ := c.Get("username")
role, _ := c.Get("role")
c.JSON(http.StatusOK, gin.H{
"user": gin.H{
"id": userID,
"username": username,
"role": role,
},
})
}
// 登出处理函数
func logout(c *gin.Context) {
// 在实际应用中,你可能需要将令牌加入黑名单
// 这里只是返回成功消息
c.JSON(http.StatusOK, gin.H{"message": "Logout successful"})
}
// 获取所有用户(仅管理员)
func getUsers(c *gin.Context) {
var users []models.User
result := database.DB.Find(&users)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch users"})
return
}
c.JSON(http.StatusOK, gin.H{"users": users})
}
7. 使用示例
注册用户:
curl -X POST http://localhost:8080/register \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"password123","role":"user"}'
登录:
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"password123"}'
访问受保护的路由:
curl -X GET http://localhost:8080/profile \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
管理员访问用户列表:
curl -X GET http://localhost:8080/admin/users \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
这个实现提供了完整的用户认证和授权功能,包括密码哈希、JWT会话管理和基于角色的权限控制。你可以根据需要扩展这个基础实现,比如添加令牌刷新、密码重置、电子邮件验证等功能。

