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

71 阅读3分钟

构建 API 接口

最简单构建 API 接口方法

相对于我之前学的Java来说,Go 语言在构建 API 接口方面简单太多了。在 Go 语言中,可以直接使用标准库中的 net/http 包来构建 API 接口并开放给用户使用。下面是一个简单的示例代码,展示了如何创建一个基本的API接口:

package main

import (
 "fmt"
 "net/http"
)

func main() {
 http.HandleFunc("/api/hello", helloHandler)
 http.ListenAndServe(":8080", nil)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintln(w, "Hello, World!")
}

代码中,使用 http.HandleFunc 函数将不同的 URL 路径与相应的处理函数关联起来。例如,/api/hello 路径与 helloHandler 函数关联,并生成了http://localhost:8080/api/hello接口地址。当客户端发送请求到这个路径时,相应的处理函数会被调用。

QQ浏览器截图20230828231634.png

使用 Gin 框架构建 API 接口

Gin 是一个用 Go(Golang)编写的Web框架,基于 httprouter,封装比较优雅,API 友好,源码注释比较明确。

Gin 具有快速灵活,容错率高,高性能等特点。支持中间件、路由组、错误管理等。它具有类似 martini 的 API,但性能要好得多,多亏了 httprouter,速度提高了40倍。

这里就不说 Gin 包的安装了,直接上代码展示。

package main

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

func main() {
    router := gin.Default()
    router.GET("/api/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, World!",
        })
    })
    router.Run(":8080")
}

用户认证

什么是用户认证

用户认证是一种信息认证技术,目的是确认用户身份和相关信息的合法性。为了在我们把接口开放给用户时,知道是哪个用户访问了这个接口,并返回对应的数据给用户,防止一些未经授权的访问和滥用。

用户认证包括用户状态认证用户个性化认证。用户状态认证是为了检查用户是否处于登录状态等;用户个性化认证是为了提取用户个性化信息。

常见的用户认证方式如下:

  • 用户名和密码认证:用户通过输入用户名和密码来验证身份。
  • 双因素认证:除了用户名和密码外,还需要通过另外一种方式进行身份验证,如手机验证码、指纹识别等。
  • 单点登录认证:用户只需登录一次,即可访问多个相关系统或应用。
  • 集成登录认证:通过 OAuth、OpenID Connect 等协议,用户可以使用其他平台(如 Google、Facebook)的账号进行登录。
  • IVR 语音认证:一般使用在金融产品设计或者产品本身需要支付给用户高价值兑换物的场景。
  • 密保问题认证:一般使用场景主要为协助用户找回用户密码。

使用JWT实现用户认证

JWT 是 JSON Web Tokens 的缩写,是一个基于 JSON 的、用于在网络上声明某种主张的令牌。

JWT 的三部分分别是头部载荷签名,头部包含算法标识和一些元信息;载荷可以存储一些用户信息;签名是对头部和载荷的哈希值进行签名,可以保证信息的完整性和真实性。

在用户登录时用 JWT 生成一个token并返回给前端存储起来,在之后的每次接口调用时,都在请求头内带上这个token来实现用户身份认证。

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
    "github.com/dgrijalva/jwt-go"
)

func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tokenString := r.Header.Get("Authorization")
        if tokenString == "" {
            http.Error(w, "未提供令牌", http.StatusUnauthorized)
            return
        }

        token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
            return []byte("secret_key"), nil
        })

        if err != nil || !token.Valid {
            http.Error(w, "令牌无效", http.StatusUnauthorized)
            return
        }
        next(w, r)
    }
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/api/hello", authMiddleware(helloHandler))
    http.Handle("/", r)
    http.ListenAndServe(":8080", nil)
}