快速開始api開發(四)登入與認證

wuyan94zl發表於2022-08-19

本文需要介紹 gotools 工具

需要使用的工具命令:gotools handler -h
程式碼地址:github.com/wuyan94zl/gotools

登入

生成

執行:gotools handler --dir users --method POST --name login

路由 POST /users/login

設定登入出入參

修改:app/types/users.go

type UsersLoginRequest struct {
    LoginID  string `json:"login_id" validate:"required,gte=6,lte=32" tip:"使用者登入名長度介於6-32位"`
    Password string `json:"password" validate:"required,gte=6,lte=32" tip:"使用者密碼長度介於6-32位"`
}

type UsersLoginResponse struct {
    ExpTime interface{} `json:"exp_time"` // 增加程式碼
    Token   interface{} `json:"token"`    // 增加程式碼
}

編寫登入邏輯

修改:app/logic/users/login.go

package users

import (
    "errors"
    "github.com/gin-gonic/gin"
    "github.com/wuyan94zl/example-api/container"
    "github.com/wuyan94zl/example-api/app/types"
    "github.com/wuyan94zl/gotools/jwt"
    "github.com/wuyan94zl/gotools/utils"
)

func LoginLogic(c *gin.Context, req *types.UsersLoginRequest) (*types.UsersLoginResponse, error) {
    info, err := container.Instance().UserModel.FindByLoginID(c.Copy(), req.LoginID)
    if err != nil {
        return nil, errors.New("使用者不存在")
    }

    if info.Password != utils.Md5ByString(req.Password+info.LoginID) {
        return nil, errors.New("密碼錯誤")
    }

    data := make(map[string]interface{})
    data["ID"] = info.ID
    data["Nickname"] = info.Nickname
    token, err := jwt.GenToken(container.Instance().Jwt, data)
    if err != nil {
        return nil, err
    }
    return &types.UsersLoginResponse{
        ExpTime: token["expTime"],
        Token:   token["token"],
    }, nil
}

認證

生成

執行 gotools handler --dir auth --method GET --name info

路由 GET /auth/info

認證中介軟體

建立:app/middleware/auth.go

package middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/wuyan94zl/example-api/container"
    "github.com/wuyan94zl/gotools/jwt"
)

func ApiAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenString := c.Request.Header.Get("Authorization")
        token, err := jwt.AuthBearerToken(container.Instance().Jwt, tokenString)
        if err != nil {
            c.JSON(401, err)
            c.Abort()
        }
        data := token["Data"].(map[string]interface{})
        for k, v := range data {
            c.Set(k, v)
        }
        // 儲存使用者到 上下文
        c.Next()
    }
}

路由

修改 router/route.go

package router

import (
    "github.com/gin-gonic/gin"
    "github.com/wuyan94zl/example-api/app/middleware"
)

func RegisterHandlers(app *gin.RouterGroup) {
    registerUsersHandler(app)
    authApp := app.Group("", middleware.ApiAuth()) // 增加認證路由組
    registerAuthHandler(authApp)// 修改傳參
}

入參出參設定

package types

type AuthInfoRequest struct{}

type AuthInfoResponse struct {
    ID       int    `json:"id"`
    Nickname string `json:"nickname"`
    HeadImg  string `json:"head_img"`
}

邏輯編寫

package auth

import (
    "github.com/gin-gonic/gin"
    "github.com/wuyan94zl/example-api/container"

    "github.com/wuyan94zl/example-api/app/types"
)

func InfoLogic(c *gin.Context, req *types.AuthInfoRequest) (*types.AuthInfoResponse, error) {
    id := c.MustGet("ID").(float64)
    info, err := container.Instance().UserModel.First(c.Copy(), int64(id))
    if err != nil {
        return nil, err
    }
    return &types.AuthInfoResponse{
        ID:       info.ID,
        Nickname: info.Nickname,
        HeadImg:  info.HeadImg,
    }, nil
}

結束

下節 定時任務 crontab 和 佇列 queue (劃重點)

本作品採用《CC 協議》,轉載必須註明作者和本文連結
沒有造飛機的格局,怎麼能擰得好螺絲。

相關文章