第3课_用户服务模块开发
热度🔥:21 免费课程
授课语音
开发用户注册、登录与身份验证功能
在构建现代 Web 应用程序时,用户身份验证和授权是至关重要的功能。本文将详细讲解如何通过 Go 架构实现用户注册、登录以及身份验证的功能。我们将使用 JWT(JSON Web Token)作为身份验证的方式,确保用户数据的安全性。
1. 用户注册功能
用户注册是 Web 应用中的基本功能之一,通常需要接受用户输入的用户名、邮箱、密码等信息,进行合法性验证,并将数据存储到数据库中。
1.1 注册接口设计
用户在提交注册信息后,我们需要验证数据的合法性,密码加密存储,并返回注册成功的消息。
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// User 定义用户表结构
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
Username string `json:"username" gorm:"unique"`
Email string `json:"email" gorm:"unique"`
Password string `json:"password"`
}
var db *gorm.DB
func init() {
// 初始化数据库连接
var err error
db, err = gorm.Open(sqlite.Open("user.db"), &gorm.Config{})
if err != nil {
log.Fatal("数据库连接失败:", err)
}
db.AutoMigrate(&User{}) // 自动迁移,创建表
}
func main() {
r := gin.Default()
// 注册路由
r.POST("/register", register)
// 启动服务器
r.Run(":8080")
}
// 注册用户
func register(c *gin.Context) {
var user User
// 解析请求中的 JSON 数据
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
// 密码加密
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
user.Password = string(hashedPassword)
// 存储用户信息到数据库
if err := db.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "注册失败"})
return
}
// 返回成功响应
c.JSON(http.StatusOK, gin.H{"message": "注册成功"})
}
解释:
- 使用
bcrypt
对用户的密码进行加密,确保密码安全。 - 使用
gorm
进行数据库操作,将用户信息保存到 SQLite 数据库中。 gin
框架用于快速处理 HTTP 请求,定义了一个POST
路由/register
用于用户注册。
2. 用户登录功能
用户登录时,我们需要验证用户输入的用户名和密码是否正确。成功验证后,返回一个 JWT(JSON Web Token)令牌,该令牌将用于后续的身份验证。
2.1 登录接口设计
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/bcrypt"
)
// 用户登录时生成 JWT Token
func login(c *gin.Context) {
var userInput User
// 解析请求中的 JSON 数据
if err := c.ShouldBindJSON(&userInput); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
var user User
// 查询数据库中是否存在该用户
if err := db.Where("username = ?", userInput.Username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
// 验证密码是否匹配
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(userInput.Password)); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
// 生成 JWT Token
token := generateToken(user.ID)
// 返回 JWT Token
c.JSON(http.StatusOK, gin.H{"token": token})
}
// 生成 JWT Token
func generateToken(userID uint) string {
// 定义密钥
secretKey := []byte("secret")
// 创建 JWT Token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(), // 令牌有效期为 24 小时
})
// 签名生成令牌
tokenString, err := token.SignedString(secretKey)
if err != nil {
log.Fatal("生成 Token 失败:", err)
}
return tokenString
}
解释:
- 用户输入的用户名和密码会与数据库中的记录进行匹配。
- 使用
bcrypt.CompareHashAndPassword
比较用户输入的密码和存储的加密密码。 - 登录成功后,调用
generateToken
生成一个 JWT,并返回给客户端。 - JWT 包含用户的
user_id
和exp
(过期时间),并使用密钥进行签名。
3. 身份验证功能
在用户登录并获得 JWT 后,后续的请求都需要附带该令牌进行身份验证。我们需要在每个请求中验证 JWT 是否有效。
3.1 中间件:验证 JWT
// 身份验证中间件
func authorizeJWT() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
// 如果没有提供 token
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "token 不能为空"})
c.Abort()
return
}
// 解析 Token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// 验证 token 签名方法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("签名方法不正确")
}
return []byte("secret"), nil
})
// 验证 token 是否有效
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的 token"})
c.Abort()
return
}
// 将用户 ID 存储到上下文中
claims := token.Claims.(jwt.MapClaims)
userID := claims["user_id"].(float64)
c.Set("user_id", userID)
c.Next()
}
}
解释:
- 中间件
authorizeJWT
会从请求头中提取Authorization
字段。 - 使用
jwt.Parse
来解析并验证 token 是否有效。 - 如果 token 无效,则返回
401 Unauthorized
错误,否则将用户 ID 存储到请求上下文中,供后续操作使用。
3.2 使用中间件保护路由
r := gin.Default()
// 注册与登录路由
r.POST("/register", register)
r.POST("/login", login)
// 需要身份验证的路由
r.GET("/profile", authorizeJWT(), func(c *gin.Context) {
userID, _ := c.Get("user_id")
c.JSON(http.StatusOK, gin.H{"user_id": userID})
})
r.Run(":8080")
解释:
r.GET("/profile", authorizeJWT(), ...)
表示该路由需要身份验证。只有携带有效的 JWT 才能访问此路由。
4. 总结
通过本课件,我们学习了如何使用 Go 实现用户注册、登录和身份验证功能。具体包括:
- 用户注册:用户通过提交数据进行注册,密码加密存储。
- 用户登录:用户通过用户名和密码登录,生成 JWT 令牌。
- 身份验证:通过 JWT 对后续请求进行身份验证,确保请求的合法性。
这些功能是构建安全的 Web 应用程序所必不可少的基础功能,掌握它们将帮助你实现更高效和安全的用户管理。