Go 语言笔记

2023 年 8 月 1 日 星期二(已编辑)
/
26
摘要
折腾 Go 语言时候记录的一些可能有用的知识
这篇文章上次修改于 2024 年 11 月 23 日 星期六,可能部分内容已经不适用,如有疑问可询问作者。

Go 语言笔记

Fiber 使用 JWT 登录验证

创建 项目

mkdir go-fiber-jwt
cd go-fiber-jwt
go mod init go-fiber-jwt

安装相关依赖

go get github.com/gofiber/fiber/v2
go get github.com/gofiber/contrib/jwt

编写 JWT 校验中间件

// jwt.go
package main

import (
    jwtware "github.com/gofiber/contrib/jwt"
    "github.com/gofiber/fiber/v2"
)

// Protected jwt 校验中间件
func Protected() fiber.Handler {
    return jwtware.New(jwtware.Config{
        SigningKey:   jwtware.SigningKey{Key: []byte("JWT密钥")},
        ErrorHandler: jwtError,
    })
}

// jwt 校验错误处理器
func jwtError(c *fiber.Ctx, _ error) error {
    return c.Status(fiber.StatusUnauthorized).SendStren("缺少 JWT 或 JWT 格式错误")
}

编写登录处理器

// login.go
package main

import (
    "fmt"
    "github.com/gofiber/fiber/v2"
    "github.com/golang-jwt/jwt/v5"
    "time"
)

// LoginRequest 登录请求
type LoginRequest struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

// Login 登录获取 token
func Login(ctx *fiber.Ctx) error {
    var err error
    loginRequest := LoginRequest{}
    // 获取登录请求体
    err = ctx.BodyParser(&loginRequest)
    if err != nil {
        return err
    }

    // TODO 检查用户名密码

    // 生成 token 返回
     jwts := jwt.New(jwt.SigningMethodHS256)
    claims := jwts.Claims.(jwt.MapClaims)
    claims["username"] = loginRequest.Username
    // 过期时间
    claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
    token, err := jwts.SignedString([]byte("JWT密钥"))
    if err != nil {
        return err
    }
    return ctx.SendString(token)
}

注册中间件和处理器

// main.go
package main

import (
    "github.com/gofiber/fiber/v2"
    "log"
    "time"
)

func main() {
    app := fiber.New()
    // 设置路由
    app.Get("/login", Login)
    // 需要保护的路由添加中间件即可
    app.Get("/hello", Protected(), func(ctx *fiber.Ctx) error {
        return ctx.SendString("hello")
    })
    // 启动
    log.Fatal(app.Listen(":8080"))
}

操作 Minio

Minio 官方提供了 Go 的 SDK,可以使用下列指令安装:

go get github.com/minio/minio-go/v7

并且提供了对应的文档:https://min.io/docs/minio/linux/developers/go/API.html

Go SDK 基本使用

初始化上下文和客户端:

package main

import (
    "context"
    "log"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
)

func main() {
    // 创建一个上下文,用于超时和取消等操作的处理,这里直接使用默认的实现
    ctx := context.Background()
    // 创建 minio 客户端
    endpoint := "127.0.1:9000"
    id := "admin"
    secret := "adminadmin"
    SessionToken := ""
    minioClient, err := minio.New(endpoint, &minio.Options{
        Creds: credentials.NewStaticV4(id, secret, SessionToken),
    })
    if err != nil {
        log.Fatalln(err)
    }
    // ...
}

上传文件:

func main() {
    // ...
    // 上传本地文件
    bucketName := "test"
    objectName := "123.jpg"
    filePath := "test.jpg"
    info, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{})
    if err != nil {
        log.Fatalln(err)
    }
    // 输出上传文件信息
    log.Printf("上传完成\n%#v", info)
}

下载文件:

func main() {
    // ...
    // 下载文件到本地
    bucketName := "test"
    objectName := "123.jpg"
    filePath := "456.jpg"
    err = minioClient.FGetObject(ctx, bucketName, objectName, filePath, minio.GetObjectOptions{})
    if err != nil {
        log.Fatalln(err)
    }
}

删除文件:

func main() {
    // ...
    // 删除文件
    bucketName := "test"
    objectName := "123.jpg"
    err = minioClient.RemoveObject(ctx, bucketName, objectName, minio.RemoveObjectOptions{})
}

使用 Gin 框架进行服务器文件上传和下载

安装 Gin 框架:

go get github.com/gin-gonic/gin

完整代码:

package main

import (
    "context"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
)

func main() {
    // 创建一个上下文,用于超时和取消等操作的处理,这里直接使用默认的实现
    ctx := context.Background()
    // 创建 minio 客户端
    endpoint := "127.0.1:9000"
    id := "admin"
    secret := "adminadmin"
    SessionToken := ""
    bucketName := "test"
    minioClient, err := minio.New(endpoint, &minio.Options{
        Creds: credentials.NewStaticV4(id, secret, SessionToken),
    })
    if err != nil {
        log.Fatalln(err)
    }
    // 创建 gin 路由
    router := gin.Default()
    // 文件上传
    router.POST("/upload", func(c *gin.Context) {
        // 读取文件
        file, _ := c.FormFile("file")
        reader, _ := file.Open()
        defer func() {
            // 关闭流
            _ = reader.Close()
        }()
        // 上传到 minio
        object, _ := minioClient.PutObject(ctx, bucketName, file.Filename, reader, file.Size, minio.PutObjectOptions{})
        // 返回上传文件的信息
        c.JSON(http.StatusOK, object)
    })
    // 文件下载
    router.GET("/file/:name", func(c *gin.Context) {
        name := c.Param("name")
        // 读取文件
        object, _ := minioClient.GetObject(ctx, bucketName, name, minio.GetObjectOptions{})
        defer func() {
            // 关闭流
            _ = object.Close()
        }()
        // 返回文件
        c.DataFromReader(http.StatusOK, -1, "application/stream", object, nil)
    })
    // 监听 8080
    _ = router.Run(":8080")
}

使用 Fiber 框架进行服务器文件上传和下载

安装 Fiber 框架:

go get github.com/gofiber/fiber/v2

完整代码:

package main

import (
    "context"
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/utils"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    "log"
)

func main() {
    // 创建一个上下文,用于超时和取消等操作的处理,这里直接使用默认的实现
    ctx := context.Background()
    // 创建 minio 客户端
    endpoint := "127.0.1:9000"
    id := "admin"
    secret := "adminadmin"
    SessionToken := ""
    bucketName := "test"
    minioClient, err := minio.New(endpoint, &minio.Options{
        Creds: credentials.NewStaticV4(id, secret, SessionToken),
    })
    if err != nil {
        log.Fatalln(err)
    }
    // 创建 fiber 路由
    app := fiber.New()
    // 文件上传
    app.Post("/upload", func(c *fiber.Ctx) error {
        // 读取文件
        file, err := c.FormFile("file")
        if err != nil {
            return err
        }
        reader, err := file.Open()
        if err != nil {
            return err
        }
        defer func() {
            // 关闭流
            _ = reader.Close()
        }()
        // 上传到 minio
        filename := utils.UUID()
        contentType := file.Header["Content-Type"][0]
        object, err := minioClient.PutObject(ctx, bucketName, filename, reader, file.Size, minio.PutObjectOptions{
            ContentType: contentType,
        })
        if err != nil {
            return err
        }
        // 返回上传文件的信息
        return c.JSON(object)
    })
    // 文件下载
    app.Get("/file/:name", func(c *fiber.Ctx) error {
        name := c.Params("name", "")
        // 读取文件
        object, err := minioClient.GetObject(ctx, bucketName, name, minio.GetObjectOptions{})
        if err != nil {
            return err
        }
        // 返回文件
        return c.SendStream(object)
    })
    // 监听 8080
    log.Fatal(app.Listen(":8080"))
}

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...