Golang项目实战--基于gin框架实现JWT身份认证

需求:

  1.RESTFul API与API版本控制

  2.中间件与jwt实现统一鉴权

  3.Controller模型绑定与参数认证

  4.protobuf消息传输

项目结构:

对鉴权逻辑这部分,要考虑到,哪些资源需要涉及到鉴权,哪些不需要涉及。比如说,对于用户登录,用户注册,这两块就不需要去鉴权,因为鉴权是在用户当前是否具有访问某一系统资源的权限。

所以,针对这部分,course表示我们要访问的资源,login表示登录逻辑(只有当用户登录成功后,服务端才会给user一个token),然后用户携带着这个token去访问具体资源。user表示用户部分逻辑,这里简单的设计成获取用户信息,创建用户信息;middleware则表示中间件,比如鉴权,我们就不需要为它单独设计一个handlerfunc了,通过中间件的形式,可以更好的减少代码的冗余的程度。

首先对于路由部分,设计如下: 

  对于course,user,router,login的设计代码如下:

//course.go
package routers

import (
    "LearningGin/JWT/course"
    "github.com/gin-gonic/gin"
)

func InitCourse(group *gin.RouterGroup) {
    v1 := group.Group("/v1")
    {
        //路径传参
        v1.GET("/course/:id", course.Get)
        v1.POST("/course", course.Add)
        v1.PUT("/course", course.Update)
        v1.DELETE("/course", course.Delete)
    }
}
//login.go
package routers

import (
    "LearningGin/JWT/login"
    "github.com/gin-gonic/gin"
)

func InitLogin(group *gin.RouterGroup) {
    v1 := group.Group("v1")
    {
        v1.GET("/login", login.Login)
    }
}
//router.go
package routers

import (
    "LearningGin/JWT/middleware"
    "github.com/gin-gonic/gin"
)

func Init(r *gin.Engine) {
    api := r.Group("/api")
    api.Use(middleware.Cors(), middleware.Auth())
    //课程相关接口
    InitCourse(api)
    //用户相互接口
    InitUser(api)

    notAuthApi := r.Group("/api")
    notAuthApi.Use()
    //登录接口
    InitLogin(notAuthApi)

}
//user.go
package routers

import (
    "LearningGin/JWT/user"
    "github.com/gin-gonic/gin"
)

func InitUser(group *gin.RouterGroup) {
    v1 := group.Group("/v1")
    {
        v1.GET("/user", user.Get)
        v1.POST("/user", user.Add)
    }
    v2 := group.Group("/v2")
    {
        v2.GET("/user", user.Get)
        v2.POST("/user", user.AddV2)
    }
}

api部分:系统资源course的CRUD,user逻辑,以及登录逻辑

//course.go
package course

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)

type course struct {
    Name     string `json:"name"form:"name"binding:"required,alphaunicode"`
    Teacher  string `json:"teacher"form:"teacher"binding:"required,alphaunicode"`
    Duration string `json:"duration"form:"duration"binding:"required,number"`
}

func Add(c *gin.Context) {
    req := &course{}
    err := c.ShouldBind(req)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }
    c.JSON(http.StatusOK, req)
    fmt.Println(*req)
}
func Get(c *gin.Context) {
    id := c.Param("id")
    c.JSON(http.StatusOK, gin.H{
        "id": id,
    })
}
func Update(c *gin.Context) {
    req := &course{}
    err := c.BindJSON(req)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }
    c.JSON(http.StatusOK, req)
}
func Delete(c *gin.Context) {
    id := c.Query("id")
    c.JSON(http.StatusOK, gin.H{
        "id": id,
    })
}
//login.go
package login

import (
    "LearningGin/JWT/jwt"
    jwt2 "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

func Login(c *gin.Context) {
    data := jwt.Data{
        Name:   "Kol",
        Age:    24,
        Gender: "male",
        StandardClaims: jwt2.StandardClaims{
            ExpiresAt: time.Now().Unix() + 60*60*24*30,
            IssuedAt:  time.Now().Unix(),
            Issuer:    "Kol",
        },
    }
    sign, err := jwt.Sign(data)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
    }
    c.JSON(http.StatusOK, gin.H{
        "access_token": sign,
    })
}
//user.go
package user

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

func Get(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "method": c.Request.Method,
        "Path":   c.Request.URL.Path,
    })
}
func Add(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "method": c.Request.Method,
        "Path":   c.Request.URL.Path,
    })
}

jwt,以及中间件部分:

//jwt.go
package jwt

import "github.com/dgrijalva/jwt-go"

type Data struct {
    Name   string
    Age    int
    Gender string
    jwt.StandardClaims
}

var key = "abcdefg1234567"

func Sign(data jwt.Claims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, data)
    sign, err := token.SignedString([]byte(key))
    if err != nil {
        return "", err
    }
    return sign, nil
}
func Verify(sign string, data jwt.Claims) error {
    _, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
        return []byte(key), nil
    })
    return err
}
//auth.go
package middleware

import (
    "LearningGin/JWT/jwt"
    "github.com/gin-gonic/gin"
    "net/http"
)

func Auth() gin.HandlerFunc {
    return func(context *gin.Context) {
        accessToken := context.Request.Header.Get("access_token")
        data := &jwt.Data{}
        err := jwt.Verify(accessToken, data)
        if err != nil {
            context.JSON(http.StatusForbidden, gin.H{
                "message": "身份认证失败",
            })
            context.Abort()
        }
        context.Set("authInfo", data)
        context.Next()
    }
}

 

posted @ 2023-06-08 21:38  99号的格调  阅读(801)  评论(0编辑  收藏  举报