golang api 服务器

发布于 / 1年前 - 更新于 / 1年前


前言

该篇文章,可以引导你使用 gin-gonic/gin ,jinzhu/gorm 和 jwt-go 搭建起一个 api web 服务器
源码地址 https://github.com/wuyan94zl/go-api

首先来个项目目录结构
image.png

路由篇

新建 routes/router.go 内容如下

package routes import ( "github.com/gin-gonic/gin" // 基于 gin 框架 ) func Register() *gin.Engine { router := gin.Default() // 获取路由实例 ApiRouter(router) // 注册路由 return router // 返回路由 }

新建 routes/api.go 内容如下

package routes import ( "github.com/gin-gonic/gin" "github.com/wuyan94zl/api/controllers" "github.com/wuyan94zl/api/middleware" ) // 注册路由列表 func ApiRouter(router *gin.Engine) { api := router.Group("/api") api.POST("/user/create", controllers.UserCreate) // 增 api.GET("/user/delete/:id", controllers.UserDelete) // 删 api.POST("/user/update/:id", controllers.UserUpdate) // 改 api.GET("/users", controllers.UserList) //查 api.POST("/user/login",controllers.UserLogin) // 登录 auth := router.Group("api") // 认证路由组 auth.Use(middleware.ApiAuth()) // 登录认证中间件 auth.GET("user/info",controllers.UserInfo) // 登录用户信息 }

路由这样拆分就够更清晰,如要增加一个管理员的路由,则增加一个 routes/admin.go 文件
然后main.go 就2行代码搞定

package main import ( "github.com/wuyan94zl/api/routes" ) func main() { router := routes.Register() router.Run(":8888") }

mysql数据库连接

数据库操作使用 GORM 扩展 查看文档

新建 database/mysql.go 文件内容如下

package database import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) var DB *gorm.DB // 定义 mysql 连接实例 var err_db error // 初始化 mysql DB 连接实例 func init() { // 单例模式获取数据库连接 实例 DB, err_db = gorm.Open("mysql", "root:123456@/blog?charset=utf8&parseTime=True&loc=Local") if err_db != nil { panic(err_db) } DB = DB.Debug() // 全局显示sql详情 // defer DB.close() // 持久连接 就不需要关闭了 }

然后使用数据库操作 database.DB.AutoMigrate(&User{}) 如下创建数据表迁移生成 users

package models import database "github.com/wuyan94zl/api/database" // 定义 表名 users 字段如下 type User struct { Id int Email string Password string Name string Age int } // 程序初始化时执行表结构迁移 func init(){ // 使用数据库操作 database.DB 为数据库连接实例 AutoMigrate(&User{}) 为创建表结构 database.DB.AutoMigrate(&User{}) }

JWT-GO

新建 auth/jwt.go 文件内容如下

package auth import ( "fmt" jwt "github.com/dgrijalva/jwt-go" "github.com/wuyan94zl/api/database" "github.com/wuyan94zl/api/models" "time" ) // 定义授权保存信息 type CustomClaims struct { Id int ExpTime int64 jwt.StandardClaims } // 私钥 const ( SECRETKEY = "wuyan-secretkey" ) // 获取用户token值 func GetToken(data *models.User) (map[string]interface{},error) { // 7200秒过期 maxAge := 7200 expTime := time.Now().Add(time.Duration(maxAge)*time.Second).Unix() customClaims := &CustomClaims{ Id: data.Id, ExpTime: expTime, StandardClaims: jwt.StandardClaims{ ExpiresAt: expTime, // 过期时间,必须设置 Issuer: "wuyan", // 非必须,也可以填充用户名, }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaims) tokenString, err := token.SignedString([]byte(SECRETKEY)) if err != nil { return nil,err } rlt := make(map[string]interface{}) rlt["expTime"] = expTime rlt["token"] = tokenString return rlt,nil } // 使用token换取user信息 func GetUser(tokenString string) (interface{}, error) { 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 claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { id := int(claims["Id"].(float64)) user := models.User{} database.DB.First(&user,id) return user,nil } else { return nil, err } }

新建 token认证中间件 middleware/auth-jwt.go

package middleware import ( "fmt" "github.com/gin-gonic/gin" "github.com/wuyan94zl/api/auth" "github.com/wuyan94zl/api/utils" ) func ApiAuth() gin.HandlerFunc { return func(c *gin.Context) { tokenString := c.Request.Header.Get("Authorization") if tokenString == "" { utils.SuccessErr(c,401,"未登录") c.Abort() return } info, err := auth.GetUser(tokenString) if err != nil { fmt.Println(err) utils.SuccessErr(c,401,"登录错误") c.Abort() return }else { // 保存用户到 上下文 c.Set("Authuser",info) c.Next() } } }

此时,需要认证的路由如下

// 定义路由组 auth := router.Group("/api") // 使用中间件 auth.Use(middleware.ApiAuth()) // 注册路由 auth.GET("info",controllers.UserInfo)

控制器获取当前登录用户

func UserInfo(c *gin.Context) { // 中间件中把用户信息存储在 上下文 `Authuser` 中 u := c.MustGet("Authuser").(models.User) utils.SuccessData(c,u) }

本作品采用《CC 协议》,转载必须注明作者和本文链接