首页 » PHP教程 » php小我登录源码技巧_7Go措辞编写小我博客 用户登录

php小我登录源码技巧_7Go措辞编写小我博客 用户登录

访客 2024-12-11 0

扫一扫用手机浏览

文章目录 [+]

还是先从models/user.go文件开始编写,写入一个构造体JwtClaims:

// JwtClaims用于天生Jwt tokentype JwtClaims struct {UserID uint `json:"user_id"`Username string `json:"username"`jwt.StandardClaims}

以上代码定义了一个名为 JwtClaims 的构造体,该构造体常日用于在 Go 运用程序中天生 JSON Web 令牌 (JWT)

php小我登录源码技巧_7Go措辞编写小我博客 用户登录

User、Username 这两个字段就不再赘述了。
jwt.StandardClaims: 这行代码嵌入了来自 jwt 包(github.com/dgrijalva/jwt-go)的 StandardClaims 构造体。
嵌入许可您在自己的构造体内重用另一个构造体的字段和方法。

总的来说 JwtClaims 构造体旨在保存天生 JWT 干系的信息。
它包括用户身份验证详细信息(UserID 和 Username),也包括来自 jwt 包定义的标准声明。

php小我登录源码技巧_7Go措辞编写小我博客 用户登录
(图片来自网络侵删)

再写入一个验证密码的函数CheckPassword:

// 验证密码func CheckPassword(hashedPassword, plainPassword string) bool {err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(plainPassword))return err == nil}

CheckPassword 的函数吸收两个字符串参数:

hashedPassword: 存储的哈希密码 (来自数据库)plainPassword: 用户输入的密码 (未加密)

函数返回一个布尔值 (bool),表示密码匹配 (true) 或不匹配 (false)。

err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(plainPassword))这行代码利用 bcrypt 包的 CompareHashAndPassword 函数进行密码比较。
它将两个切片 ([]byte) 作为参数:

第一个切片 ([]byte(hashedPassword)) 将存储的哈希密码转换为字节切片。
第二个切片 ([]byte(plainPassword)) 将用户输入的密码转换为字节切片。

CompareHashAndPassword 函数比较两个密码的哈希值之后将其结果存储在 err 变量中。

return err == nil 通过比较 err 是否为 nil 来判断密码是否匹配,并返回相应的布尔值 (true 或 false)。

当有了存储JWT的构造体和验证密码的函数后,我们就可以去写天生用户令牌和用户登录的的代码了。

在utils目录中新建文件jwt.go,并写入如下内容:

package utilsimport ("time""xblog/models""github.com/dgrijalva/jwt-go")var jwtSecret = []byte("my_secret_key")// GenerateToken天生用户令牌func GenerateToken(userID uint, username string) (string, error) {now := time.Now()claims := models.JwtClaims{UserID: userID,Username: username,StandardClaims: jwt.StandardClaims{ExpiresAt: now.Add(time.Hour 24 7).Unix(), // 一周有效期Issuer: "xblog",},}token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)return token.SignedString(jwtSecret)}

此文件目前只包含了一个函数(GenerateToken),也是我要重点先容的。

var jwtSecret = []byte("my_secret_key") 定义了一个名为 jwtSecret 的全局变量,用于存储 JWT 署名利用的密钥。
把稳,这是一个示例密钥,请勿将其用于生产环境中。
func GenerateToken(userID uint, username string) (string, error) 定义了一个名为 GenerateToken 的函数。
函数吸收两个参数:userID: 用户 ID (类型为 uint) username: 用户名 (类型为 string)。
该函数返回两个值:天生的 JWT 令牌 (类型为 string) 发生缺点时返回的缺点工具 (类型为 error)now := time.Now(): 获取当前韶光。
claims := models.JwtClaims{ ... } 创建一个 models.JwtClaims 构造体的实例 (models.JwtClaims 已经在 xblog/models 包中完成)。
设置构造体字段的值: UserID: 利用传入的 userID 参数。
Username: 利用传入的 username 参数。
StandardClaims: 嵌入 jwt.StandardClaims 构造体,并设置以下字段: ExpiresAt: 令牌的过期韶光为当前韶光加上 7 天 (利用 time.Hour 24 7)。
Issuer: 令牌的颁发者为 "xblog"。
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims): 利用 jwt-go 库创建新的 JWT 令牌。
第一个参数指定署名方法为 HMAC SHA-256 ( jwt.SigningMethodHS256 )。
第二个参数是之前创建的 claims 构造体。
return token.SignedString(jwtSecret): 利用预先定义的 jwtSecret 密钥对令牌进行署名,并返回署名的字符串

总的来说 GenerateToken 函数用于天生一个包含用户 ID、用户名、过期韶光和颁发者信息的 JWT 令牌。
这个令牌可以用来验证用户身份并付与访问权限。

在utils目录中新建文件auth.go,大概只看文件名你就能想到它的用场。
写入如下内容:

package utilsimport ("errors""net/http""strings""xblog/models""github.com/dgrijalva/jwt-go""github.com/gin-gonic/gin""gorm.io/gorm")// Login 用户上岸func Login(username, password string) (user models.User, err error) {user = &models.User{}// 直接查询用户。
如果存在,则加载详细信息;如果不存在,则返回缺点信息result := models.DB.Where("username = ?", username).First(user)if errors.Is(result.Error, gorm.ErrRecordNotFound) {return nil, errors.New("用户名或密码缺点") // 返回通用缺点信息} else if result.Error != nil {return nil, result.Error // 返回其它数据库查询缺点}// 验证密码if !models.CheckPassword(user.Password, password) {return nil, errors.New("用户名或密码缺点") // 返回通用缺点信息}return user, nil}// RequireAuth是验证Jwt的中间件func RequireAuth(c gin.Context) {authToken := c.GetHeader("Authorization")if authToken == "" {c.JSON(http.StatusUnauthorized, gin.H{"error": "未供应认证令牌"})c.Abort()return}parts := strings.Fields(authToken)if len(parts) < 2 || parts[0] != "Bearer" {c.JSON(http.StatusUnauthorized, gin.H{"error": "认证令牌格式缺点"})c.Abort()return}tokenStr := parts[1]claims := &models.JwtClaims{}token, err := jwt.ParseWithClaims(tokenStr, claims, func(token jwt.Token) (interface{}, error) {return jwtSecret, nil})if err != nil || !token.Valid {c.JSON(http.StatusUnauthorized, gin.H{"error": "认证令牌无效"})c.Abort()return}// 验证通过后,将用户信息设置到Context中,供后续处理函数利用c.Set("currentUser", claims)c.Next()}

Login 该函数用于用户登录,验证用户名和密码是否精确,并返回用户信息。
它吸收两个参数:username: 用户名 password: 密码 (类型是 string)。
同样返回两值:user: 登录成功后返回的用户信息 (类型为 models.User) err: 登录失落败时返回的缺点信息 (类型为 error)

函数内部逻辑:

利用 models.DB 查询是否存在指定用户名的用户。
如果用户不存在,则返回 errors.New("用户名或密码缺点") 缺点。
如果用户存在,则加载用户详细信息。
利用 models.CheckPassword 函数验证用户输入的密码是否精确。
如果密码缺点,则返回 errors.New("用户名或密码缺点") 缺点。
如果验证通过,则返回用户信息和 nil 缺点。

RequireAuth 该函数用于验证用户是否携带并拥有有效的 JWT 令牌。
它只吸收一个类型为 gin.Context的参数(Gin 框架的高下文)

函数内部逻辑:

从要求头中获取 Authorization 字段的值,即 JWT 令牌。
如果 Authorization 字段为空,则返回 http.StatusUnauthorized 状态码和缺点信息 "未供应认证令牌"。
将 Authorization 字段的值分割成两部分,并检讨格式是否精确。
如果格式禁绝确,则返回 http.StatusUnauthorized 状态码和缺点信息 "认证令牌格式缺点"。
利用 jwt.ParseWithClaims 函数解析 JWT 令牌,并将其结果存储在 claims 构造体中。
如果解析失落败或令牌无效,则返回 http.StatusUnauthorized 状态码和缺点信息 "认证令牌无效"。
如果验证通过,则将用户信息设置到 Gin 高下文中,供后续处理函数利用。

总结:这两个函数共同实现了用户认证功能,确保只有拥有有效令牌的用户才能访问须要权限的资源。

接下来便是API接口和路由了。

打开api/user.go文件,编写如下代码:

func UserLogin(c gin.Context) {var u models.Userif err := c.ShouldBindJSON(&u); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error(),})return}user, err := utils.Login(u.Username, u.Password)if err != nil {c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error(),})return}token, err := utils.GenerateToken(user.ID, user.Username)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error(),})return}c.JSON(http.StatusOK, gin.H{"token": token,})}

UserLogin 该函数用于处理用户登录要求。
让我们来详细分解一下:

1. var u models.User

声明了一个名变量 u,类型为 models.User。

2. if err := c.ShouldBindJSON(&u); err != nil {

考试测验从要求体中解析 JSON 数据并将其绑定到变量 u 上。
如果解析过程中涌现缺点 (err != nil),则实行后续代码块。

3. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})

解析 JSON 数据出错时实行到这里。
向客户端返回 JSON 相应,状态码为 http.StatusBadRequest (要求格式缺点)。
相应体包含 "error" 键,值为解析缺点信息 err.Error()。

4. user, err := utils.Login(u.Username, u.Password)

调用 utils.Login 函数考试测验登任命户,利用 u.Username 和 u.Password 进行验证。
登录成功后,user 变量会存储返回的用户信息 (类型为 models.User)。

5. if err != nil {

检讨 utils.Login 函数返回的缺点 (err)。
如果登录失落败 (err != nil) 实行后续代码块。

6. c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})

向客户端返回 JSON 相应,状态码为 http.StatusUnauthorized (未授权)。
相应体包含 "error" 键,值为登录失落败信息 err.Error()。

7. token, err := utils.GenerateToken(user.ID, user.Username)

如果登录成功,调用 utils.GenerateToken 函数天生 JWT 令牌。
利用登录成功返回的用户信息 (user.ID 和 user.Username) 作为参数天生令牌。
天生的 JWT 令牌会存储在 token 变量中。

8. if err != nil {

检讨 utils.GenerateToken 函数返回的缺点 (err)。
天生令牌失落败 (err != nil) 时实行后续代码块。

9. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})

向客户端返回 JSON 相应,状态码为 http.StatusInternalServerError (做事器内部缺点)。
相应体包含 "error" 键,值为天生令牌失落败信息 err.Error()。

10. c.JSON(http.StatusOK, gin.H{"token": token})

如果登录和天生令牌都成功,利用 c.JSON 方法向客户端返回 JSON 相应。
状态码为 http.StatusOK (要求成功)。
相应体包含 "token" 键,值为天生的 JWT 令牌 (token)。

完成上述代码后保存,如果IDE不能自动添加"xblog/utils",我们在import中手动添加它。

末了一步。
在router.go文件(路由)中写入用户登录的路由:

public := r.Group("api/v1"){public.POST("user/add", api.UserAdd)public.POST("user/login", api.UserLogin)}

好,接下来我们利用如下CURL测试一下:

# 测试Logincurl -X POST \-H "Content-Type: application/json" \-d '{"username":"user1","password":"passwd123"}' \http://10.0.0.185:8000/api/v1/user/login; echo

由图片可知,程序成功返回用户登录后的token。

标签:

相关文章