构建 API 接口 & 用户认证 | 青训营

51 阅读4分钟

为什么需要 API 接口

API 接口和用户认证是现代应用程序中常见的关键组件,它们在应用程序开发和安全性方面发挥着重要的作用。

API 接口

  • 提供了应用程序与其他服务或应用程序进行交互的标准方式。
  • 允许不同的系统、平台或团队之间进行数据交换和通信。
  • 通过定义清晰的接口规范,简化了应用程序之间的集成和开发过程。
  • 提供了灵活性,使得应用程序可以与第三方服务、移动应用、Web 前端等进行通信。
  • 促进了应用程序的可扩展性和模块化,使得不同组件可以独立开发、测试和部署。

用户认证

  • 确保只有经过身份验证的用户才能访问应用程序或特定的功能。
  • 提供了安全性和隐私保护,防止未经授权的用户获取敏感数据。
  • 建立了用户身份的信任关系,允许应用程序在用户参与的环境中执行相关操作。
  • 可以跟踪和审计用户的活动,以便进行安全监控和追溯。

综上所述,API 接口和用户认证对于构建安全、可靠、可扩展的应用程序至关重要。它们提供了一种标准化的交互方式,并确保只有经过授权的用户才能访问应用程序的相关资源和功能。

定义 API 接口

每个接口应该有一个易于理解的名称、HTTP方法(如GET、POST、PUT、DELETE等)以及相关的URL路径。例如:

  • GET /api/users:获取所有用户列表

  • GET /api/users/{id}:获取特定ID的用户详情

  • POST /api/users:创建新的用户

  • PUT /api/users/{id}:更新特定ID的用户

  • DELETE /api/users/{id}:删除特定ID的用户

// 步骤1:定义API接口
type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

var users []User

选择HTTP路由器和Web框架

选择一个适合的HTTP路由器和Web框架来帮助你构建和管理API接口。一些常用的选择包括:Gin、Echo、net/http,这里我选择常用的 Gin 框架作为示例。

实现 API 接口

在选择的框架中,按照第一步中定义的接口实现相应的API端点。确保在每个端点中编写逻辑,以实现对数据的增删改查操作。

package main

import (
	"net/http"
	"strconv"

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

// 步骤1:定义API接口
type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

var users []User

func main() {
	// 创建默认的 Gin 路由引擎
	router := gin.Default()

	// 定义 API 路由
	router.GET("/api/users", getUsers)
	router.GET("/api/users/:id", getUserByID)
	router.POST("/api/users", createUser)
	router.PUT("/api/users/:id", updateUser)
	router.DELETE("/api/users/:id", deleteUser)

	// 在端口 8080 上运行服务器
	router.Run(":8080")

}

// 获取所有用户
func getUsers(c *gin.Context) {
	c.JSON(http.StatusOK, users)
}

// 根据 ID 获取特定用户
func getUserByID(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}

	for _, user := range users {
		if user.ID == id {
			c.JSON(http.StatusOK, user)
			return
		}
	}

	c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
}

// 创建新的用户
func createUser(c *gin.Context) {
	var newUser User
	if err := c.ShouldBindJSON(&newUser); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	newUser.ID = len(users) + 1
	users = append(users, newUser)
	c.JSON(http.StatusCreated, newUser)
}

// 根据 ID 更新用户
func updateUser(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}

	var updatedUser User
	if err := c.ShouldBindJSON(&updatedUser); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	for i, user := range users {
		if user.ID == id {
			updatedUser.ID = id
			users[i] = updatedUser
			c.JSON(http.StatusOK, updatedUser)
			return
		}
	}

	c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
}

// 根据 ID 删除博文
func deleteUser(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
		return
	}

	for i, user := range users {
		if user.ID == id {
			users = append(users[:i], users[i+1:]...)
			c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
			return
		}
	}

	c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
}

添加用户认证

为了实现用户认证,我们将使用JWT(JSON Web Token)进行令牌身份验证。我们需要安装github.com/dgrijalva/jwt-go库,然后实现用户认证和令牌生成

// 定义秘钥
const secretKey = "API 以及用户认证测试"

func main() {
	// 创建默认的 Gin 路由引擎
	router := gin.Default()

	// 添加用户认证中间件
	router.Use(authMiddleware())

	// 定义 API 路由
	router.POST("/login", login) // 用户登录
	router.GET("/api/users", getUsers)
	router.GET("/api/users/:id", getUserByID)
	router.POST("/api/users", createUser)
	router.PUT("/api/users/:id", updateUser)
	router.DELETE("/api/users/:id", deleteUser)

	// 在端口 8080 上运行服务器
	router.Run(":8080")

}

// 用户信息,模拟数据库中的用户
var userInfo = map[string]string{
	"user1": "password1",
	"user2": "password2",
}

var loginData struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// 处理用户登录
func login(c *gin.Context) {

	if err := c.ShouldBindJSON(&loginData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	expectedPassword, ok := userInfo[loginData.Username]
	if !ok || loginData.Password != expectedPassword {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	token := generateToken(loginData.Username)
	c.JSON(http.StatusOK, gin.H{"token": token})
}

// 生成 JWT Token
func generateToken(username string) string {
	expirationTime := time.Now().Add(15 * time.Minute)
	claims := jwt.StandardClaims{
		ExpiresAt: expirationTime.Unix(),
		Subject:   username,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, _ := token.SignedString([]byte(secretKey))
	return tokenString
}

// JWT 认证中间件
func authMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "No token provided"})
			c.Abort()
			return
		}

		token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(secretKey), nil
		})

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

		c.Next()
	}
}

测试 API 接口和用户认证

使用Postman测试实现的功能,结果如下: image.png