zdpgo_gin_jwt 专为zdpgo_gin打造的JWT权限校验中间件,当需要实现基于JWT Token的权限校验的时候可以考虑使用此框架

zdpgo_gin_jwt

专为zdpgo_gin打造的JWT权限校验中间件,当需要实现基于JWT Token的权限校验的时候可以考虑使用此框架

使用教程

快速入门

go 复制代码
package main

import (
	"log"
	"net/http"
	"os"
	"time"

	gin "github.com/zhangdapeng520/zdpgo_gin"
	jwt "github.com/zhangdapeng520/zdpgo_gin_jwt"
)

// 登录请求结构体
type login struct {
	Username string `form:"username" json:"username" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

var (
	identityKey = "id"
	port        string
)

// User 用户模型
type User struct {
	UserName  string
	FirstName string
	LastName  string
}

func init() {
	port = os.Getenv("PORT")
	if port == "" {
		port = "8000"
	}
}

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

	// 创建中间件
	authMiddleware, err := jwt.New(initParams())
	if err != nil {
		log.Fatal("JWT Error:" + err.Error())
	}

	// 注册中间件
	engine.Use(handlerMiddleWare(authMiddleware))

	// 注册路由
	registerRoute(engine, authMiddleware)

	// 启动服务
	if err = http.ListenAndServe(":"+port, engine); err != nil {
		log.Fatal(err)
	}
}

// 注册路由
func registerRoute(r *gin.Engine, handle *jwt.GinJWTMiddleware) {
	r.POST("/login", handle.LoginHandler)               // 登录
	r.NoRoute(handle.MiddlewareFunc(), handleNoRoute()) // 404

	// 需要权限的路由
	auth := r.Group("/auth", handle.MiddlewareFunc())
	auth.GET("/refresh_token", handle.RefreshHandler)
	auth.GET("/hello", helloHandler)
}

// 处理中间件
func handlerMiddleWare(authMiddleware *jwt.GinJWTMiddleware) gin.HandlerFunc {
	return func(context *gin.Context) {
		errInit := authMiddleware.MiddlewareInit()
		if errInit != nil {
			log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
		}
	}
}

// 初始化中间件参数
func initParams() *jwt.GinJWTMiddleware {
	return &jwt.GinJWTMiddleware{
		Realm:       "test zone",
		Key:         []byte("secret key"),
		Timeout:     time.Hour,
		MaxRefresh:  time.Hour,
		IdentityKey: identityKey,
		PayloadFunc: payloadFunc(),

		IdentityHandler: identityHandler(),
		Authenticator:   authenticator(),
		Authorizator:    authorizator(),
		Unauthorized:    unauthorized(),
		TokenLookup:     "header: Authorization, query: token, cookie: jwt",
		// TokenLookup: "query:token",
		// TokenLookup: "cookie:token",
		TokenHeadName: "Bearer",
		TimeFunc:      time.Now,
	}
}

func payloadFunc() func(data interface{}) jwt.MapClaims {
	return func(data interface{}) jwt.MapClaims {
		if v, ok := data.(*User); ok {
			return jwt.MapClaims{
				identityKey: v.UserName,
			}
		}
		return jwt.MapClaims{}
	}
}

func identityHandler() func(c *gin.Context) interface{} {
	return func(c *gin.Context) interface{} {
		claims := jwt.ExtractClaims(c)
		return &User{
			UserName: claims[identityKey].(string),
		}
	}
}

// 校验账号密码
func authenticator() func(c *gin.Context) (interface{}, error) {
	return func(c *gin.Context) (interface{}, error) {
		var loginVals login
		if err := c.ShouldBind(&loginVals); err != nil {
			return "", jwt.ErrMissingLoginValues
		}
		userID := loginVals.Username
		password := loginVals.Password

		if userID == "zhangdapeng" && password == "zhangdapeng520" {
			return &User{
				UserName:  userID,
				LastName:  "Bo-Yi",
				FirstName: "Wu",
			}, nil
		}
		return nil, jwt.ErrFailedAuthentication
	}
}

func authorizator() func(data interface{}, c *gin.Context) bool {
	return func(data interface{}, c *gin.Context) bool {
		if v, ok := data.(*User); ok && v.UserName == "admin" {
			return true
		}
		return false
	}
}

func unauthorized() func(c *gin.Context, code int, message string) {
	return func(c *gin.Context, code int, message string) {
		c.JSON(code, gin.H{
			"code":    code,
			"message": message,
		})
	}
}

func handleNoRoute() func(c *gin.Context) {
	return func(c *gin.Context) {
		claims := jwt.ExtractClaims(c)
		log.Printf("NoRoute claims: %#v\n", claims)
		c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
	}
}

func helloHandler(c *gin.Context) {
	claims := jwt.ExtractClaims(c)
	user, _ := c.Get(identityKey)
	c.JSON(200, gin.H{
		"userID":   claims[identityKey],
		"userName": user.(*User).UserName,
		"text":     "Hello World.",
	})
}

访问登录接口:

bash 复制代码
req -X POST -H 'Content-Type:application/json' -d '{\"username\":\"zhangdapeng\",\"password\":\"zhangdapeng520\"}' http://localhost:8000/login

访问hello接口:

bash 复制代码
req http://127.0.0.1:8000/hello

携带Token访问hello接口:

bash 复制代码
req -H 'Authorization: Bearer Token' http://127.0.0.1:8000/hello
req -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjM1MTMxOTIsImlkIjoiemhhbmdkYXBlbmciLCJvcmlnX2lhdCI6MTcyMzUwOTU5Mn0.gbFGsjCxFymMv4uQtVPmbOTiX8ScKONO80lfwZcAFEg' http://127.0.0.1:8000/hello

版本

v0.1.0

  • 基本用法

实际测试

在开发此框架的时候,我进行了实际的测试。

首先是访问登录接口:

bash 复制代码
req -X POST -H 'Content-Type:application/json' -d '{\"username\":\"zhangdapeng\",\"password\":\"zhangdapeng520\"}' http://localhost:8000/login

访问登录接口以后,会给我们返回一个Token,这个Token非常重要,是用来实现权限校验的重要信息。

接着,我们使用Token请求hello接口:

bash 复制代码
req -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjM1MTMxOTIsImlkIjoiemhhbmdkYXBlbmciLCJvcmlnX2lhdCI6MTcyMzUwOTU5Mn0.gbFGsjCxFymMv4uQtVPmbOTiX8ScKONO80lfwZcAFEg' http://127.0.0.1:8000/hello

如果我们访问hello接口的时候不携带Token是不会返回正确的信息的:

bash 复制代码
req http://127.0.0.1:8000/hello

当然,如果你传递的是一个错误的Token,也是不行的:

bash 复制代码
req -H 'Authorization: Bearer abc' http://127.0.0.1:8000/hello

更多资料

如果你需要更详细的视频课程或者一对一的私教指导,欢迎留言或者私信哈

相关推荐
佳腾_1 天前
【消息队列kafka_中间件】一、快速入门分布式消息队列
分布式·云原生·中间件·kafka
ErizJ1 天前
Go 微服务框架 | 中间件
微服务·中间件·golang
唐人街都是苦瓜脸2 天前
Kafka和RocketMQ相比有什么区别?那个更好用?
分布式·中间件·kafka·rocketmq
还是鼠鼠3 天前
Node.js局部生效的中间件
javascript·vscode·中间件·node.js·json·express
爱的叹息4 天前
数据库分库分表中间件及对比
数据库·中间件
和尚用0飘柔04 天前
【中间件】使用ElasticSearch提供的RestClientAPI操作ES
大数据·elasticsearch·中间件
还是鼠鼠5 天前
Node.js自定义中间件
javascript·vscode·中间件·node.js·json·express
还是鼠鼠6 天前
Node.js中间件的5个注意事项
javascript·vscode·中间件·node.js·json·express
ChinaRainbowSea7 天前
1. 初始 RabbitMQ 消息队列
java·中间件·rabbitmq·java-rabbitmq
还是鼠鼠8 天前
Node.js全局生效的中间件
javascript·vscode·中间件·node.js·json·express