zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【GO】K8s 管理系统项目14[API部分--中间件]

2023-09-14 09:02:04 时间

【GO】K8s 管理系统项目[API部分–中间件]

1. Cors跨域

middle/cors.go

package middle

import (
	"net/http"

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

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		//获取请求方法
		method := c.Request.Method

		//添加跨域响应头
		c.Header("Content-Type", "application/json")
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Max-Age", "86400")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
		c.Header("Access-Control-Allow-Headers", "X-Token, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
		c.Header("Access-Control-Allow-Credentials", "false")

		//放行OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		//处理请求
		c.Next()
	}
}

2. JWT Token验证

验证请求的合法性,前端只有在登录状态下才会生成token,请求时将token放入Header中,后端接收的请求时,先由该中间件验证token是否合法,合法时才放行,继续执行业务函数的逻辑处理。

utils/jwt.go

package utils

import (
	"errors"
	"github.com/dgrijalva/jwt-go"
	"github.com/wonderivan/logger"
	"golang.org/x/oauth2/jwt"
)

var JWTToken jwtToken

type jwtToken struct{}

//定义token中携带的信息
type CustomClaims struct {
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}

//加解密因子
const (
	SECRET = "adoodevops"
)

//解析Token
func (*jwtToken) ParseToken(tokenString string) (claims *CustomClaims, err error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(SECRET), nil
	})
	if err != nil {
		logger.Error("parse token failed ", err)
		//处理token解析后的各种错误
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, errors.New("TokenMalformed")
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				return nil, errors.New("TokenExpired")
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, errors.New("TokenNotValidYet")
			} else {
				return nil, errors.New("TokenInvalid")
			}
		}
	}

	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("解析Token失败")
}

middle/jwt.go

package middle

import (
	"k8s-plantform/utils"

	"github.com/gin-gonic/gin"

	"net/http"
)

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		//对登录接口放行
		if len(c.Request.URL.String()) >= 10 && c.Request.URL.String()[0:10] == "/api/login" {
			c.Next()
		} else {
			//处理验证逻辑
			token := c.Request.Header.Get("Authorization")
			if token == "" {
				c.JSON(http.StatusBadRequest, gin.H{
					"msg":  "请求未携带token,无权限访问",
					"data": nil,
				})
				c.Abort()
				return
			}
			//解析token内容
			claims, err := utils.JWTToken.ParseToken(token)
			if err != nil {
				//token过期错误
				if err.Error() == "TokenExpired" {
					c.JSON(http.StatusBadRequest, gin.H{
						"msg":  "授权已过期",
						"data": nil,
					})
					c.Abort()
					return
				}
				//其他解析错误
				c.JSON(http.StatusBadRequest, gin.H{
					"msg":  err.Error(),
					"data": nil,
				})
				c.Abort()
				return
			}
			c.Set("claims", claims)
			c.Next()
		}
	}
}

3. 在main中调用

main.go

package main

import (
	"fmt"
	"k8s-plantform/config"
	"k8s-plantform/controller"
	"k8s-plantform/db"
	"k8s-plantform/middle"
	"k8s-plantform/service"

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

func main() {
	// 初始化数据库
	db.Init()
	// 初始化k8s client
	service.K8s.Init()
	// 初始化gin
	r := gin.Default()
	// 加载jwt中间件
	r.Use(middle.JWTAuth())
	// 加载跨域中间件
	r.Use(middle.Cors())
	// 初始化路由
	controller.Router.InitApiRouter(r)

	// gin 程序启动
	//r.Run(config.ListenAdd)
	fmt.Println("http://192.168.31.1:9091/")
	r.Run(config.ListenAddr)
	// 关闭数据库
	db.Close()
}

4. 测试jwt

测试再访问就会提示:“请求未携带token,无权限访问”

请添加图片描述