基于golang的认证和鉴权

96 阅读1分钟

此处所采用的乃是 Go 语言的 Gin 框架,借助中间件这一途径来达成认证与鉴权之目的。

认证

基于请求头中的 Authorization 来开展认证工作,判别 token 是否存在,token 是否合法,将 token 中的角色信息等存置于上下文中。

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == "" {
			utils.ResponseWithError(c, http.StatusUnauthorized, "未授权")
			c.Abort()
			return
		}
		token = strings.TrimPrefix(token, "Bearer ")
		tokenMD5, err := config.RedisClient.Get(c, token).Result()
		if err != nil {
			utils.ResponseWithError(c, http.StatusUnauthorized, "token不存在")
			c.Abort()
			return
		}
		// 解析 token
		claims, err := utils.ParseToken(tokenMD5)
		if err != nil {
			utils.ResponseWithError(c, http.StatusUnauthorized, "无效的 token")
			c.Abort()
			return
		}
		// 将解析后的内容存入上下文
		c.Set("permissions", claims["permissions"])
		c.Set("userId", claims["userId"])
		// 继续执行
		c.Next()
	}
}

鉴权

凭借上下文中的角色信息来实施鉴权操作

func AuthorizationMiddleware(requiredPermissions []string) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取用户权限列表
        permissions, exists := c.Get("permissions")
        if !exists {
            utils.ResponseWithError(c, http.StatusForbidden, "权限信息缺失")
            c.Abort()
            return
        }

        // 转换成 []string
        userPermissions, ok := permissions.([]string)
        if !ok {
            utils.ResponseWithError(c, http.StatusForbidden, "权限数据格式错误")
            c.Abort()
            return
        }

        // 检查用户是否拥有所需的权限
        for _, requiredPermission := range requiredPermissions {
            if !contains(userPermissions, requiredPermission) {
                utils.ResponseWithError(c, http.StatusForbidden, "权限不足")
                c.Abort()
                return
            }
        }

        // 如果权限匹配,继续执行
        c.Next()
    }
}

// 检查权限列表是否包含某个权限
func contains(permissions []string, permission string) bool {
    for _, p := range permissions {
        if p == permission {
            return true
        }
    }
    return false
}

在路由中使用

r := gin.Default()

// 认证中间件
r.Use(AuthMiddleware())

// 使用鉴权中间件
r.GET("/admin", AuthorizationMiddleware("admin"), func(c *gin.Context) {
    // 只有管理员才能访问这个路由
    c.JSON(http.StatusOK, gin.H{"message": "Welcome Admin!"})
})

r.GET("/user", AuthorizationMiddleware("user"), func(c *gin.Context) {
    // 只有普通用户才能访问这个路由
    c.JSON(http.StatusOK, gin.H{"message": "Welcome User!"})
})