极客时间初级Go工程师训练营
核心代码,注释必读
// download:
链接: https://pan.baidu.com/s/1_76lIW6L_nnDJ-hnOwZTJw?pwd=6zf2 提取码: 6zf2
Gin和GORM介绍
Gin是一个非常流行的Go语言Web框架,具有快速、高效和轻量级等特点。它可以帮助我们快速构建RESTful API或Web应用程序。
而GORM是一个Go语言的ORM库,它的目的是简化对SQL数据库的操作。它支持多种数据库(MySQL、PostgreSQL、SQLite等),可以通过结构体进行数据建模,提供了丰富的查询功能。
用户注册登录功能实现
功能需求
我们要实现一个用户注册登录功能,包括以下功能:
- 用户注册:用户通过用户名和密码注册账号;
- 用户登录:用户通过用户名和密码登录账号,如果登录成功则返回一个令牌(token);
- 获取用户信息:用户通过令牌获取自己的信息。
数据模型设计
我们需要一个User数据模型来存储用户信息,包含以下字段:
- ID:用户ID;
- Username:用户名;
- PasswordHash:密码哈希值。
type User struct {
gorm.Model
Username string `gorm:"unique_index"`
PasswordHash string
}
注册功能实现
用户注册是将用户名和密码存储到数据库中,我们需要这样做:
func Register(c *gin.Context) {
var user User
// 解析请求中的JSON数据到user变量中
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 如果用户名已经存在,则返回错误
if db.Where("username = ?", user.Username).First(&User{}).Error == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "username already exists"})
return
}
// 将用户密码进行哈希
passwordHash, err := bcrypt.GenerateFromPassword([]byte(user.PasswordHash), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
user.PasswordHash = string(passwordHash)
// 将用户保存到数据库中
if err := db.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 返回成功信息
c.JSON(http.StatusOK, gin.H{"message": "user created"})
}
上面代码中:
- 我们使用
ShouldBindJSON函数将请求中的JSON数据绑定到user变量上; - 我们使用
db.Where函数查询是否已经存在相同的用户名; - 我们使用
bcrypt库对密码进行哈希处理; - 我们使用
db.Create函数将用户存储到数据库中; - 在最后,我们返回成功信息。
登录功能实现
用户登录是验证用户提供的用户名和密码是否与数据库中的相同。我们需要这样做:
func Login(c *gin.Context) {
var user User
// 解析请求中的JSON数据到user变量中
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 检查用户是否存在
if db.Where("username = ?", user.Username).First(&user).Error != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid username or password"})
return
}
// 检查密码是否正确
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(user.PasswordHash)); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid username or password"})
return
}
// 创建JWT令牌
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["user_id"] = user.ID
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
// 签名令牌并返回
tokenString, err := token.SignedString([]byte("secret"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H