如何将我的服务开放给用户:构建 API 接口和用户认证的实践指南

114 阅读2分钟

gin框架简介

构建web api接口一般用到http框架, golang的常用http框架有gin、Beego、Buffalo、Echo、Hertz等。使用http框架可以很方便向用户开放自己的api接口。 gin 的特性:

快速

基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。

支持中间件

传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。

Crash 处理

Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!

JSON 验证

Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。

路由组

更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。

错误管理

Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。

内置渲染

Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。

可扩展性

新建一个中间件非常简单,去查看示例代码吧。

gin 框架快速使用

下载安装:

$ go get -u github.com/gin-gonic/gin

引入代码

import "github.com/gin-gonic/gin"

获取router

r := gin.Default()

得到router之后可以注册路由

r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})

启动服务:

r.Run() // 监听并在 0.0.0.0:8080 上启动服务

gin 框架中间件扩展

框架通过use方法设置中间件

// Use attaches a global middleware to the router. ie. the middleware attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
}

扩展中间件需要实现HandlerFunc接口

jwt认证

gin框架可以很方便使用中间件完成JWT认证

使用第三方库

go get -u github.com/gin-gonic/gin go get -u github.com/dgrijalva/jwt-go

使用示例:

package main

import (
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
    "github.com/dgrijalva/jwt-go"
)

var (
    jwtSecret = []byte("your-secret-key") // 用于生成和验证JWT的密钥
)

// 创建一个JWT
func createToken(userId int) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "userId": userId,
        "exp":    time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为一天
    })
    tokenString, err := token.SignedString(jwtSecret)
    return tokenString, err
}

// JWT中间件
func authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenString := c.GetHeader("Authorization")

        if tokenString == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
            c.Abort()
            return
        }

        token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
            return jwtSecret, nil
        })

        if err != nil || !token.Valid {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
            c.Abort()
            return
        }

        c.Next()
    }
}

func main() {
    r := gin.Default()

    // 登录路由,生成JWT并返回给客户端
    r.POST("/login", func(c *gin.Context) {
        userId := 123 // 这里应该是从数据库或其他地方获取的用户ID
        token, err := createToken(userId)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"token": token})
    })

    // 受保护的路由,需要通过JWT验证
    r.GET("/protected", authMiddleware(), func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "Access granted"})
    })

    r.Run(":8080")
}