Golang Gin系列-7:认证和授权

在本章中,我们将探讨Gin框架中身份验证和授权的基本方面。这包括实现基本的和基于令牌的身份验证,使用基于角色的访问控制,应用中间件进行授权,以及使用HTTPS和漏洞防护保护应用程序。

在这里插入图片描述

实现身份认证

Basic 认证

Basic 认证是内置于HTTP协议中的简单身份验证方案。它包括在每个请求中发送用户名和密码。尽管它很容易实现,但出于安全考虑,不建议将其用于生产环境应用程序。

示例:Basic 认证

package main

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

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

    authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
        "admin": "password123",
    }))

    authorized.GET("/protected", func(c *gin.Context) {
        user := c.MustGet(gin.AuthUserKey).(string)
        c.JSON(http.StatusOK, gin.H{"user": user, "message": "Welcome to the protected route!"})
    })

    r.Run()
}

在这个例子中,杜松子酒。BasicAuth中间件检查有效的用户名和密码。如果凭证正确,则继续请求;否则,它返回401 Unauthorized状态。

Token-based认证

Token-based认证,特别是使用JSON Web令牌(JWT),是一种更安全、可扩展的方法。jwt是无状态的,这意味着服务器不需要存储会话信息。
在这里插入图片描述

示例:Token-based认证

在本例中,“login”端点为有效凭证生成JWT,“authenticateJWT”中间件检查token的有效性。

package main

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

var jwtKey = []byte("my_secret_key")

type Claims struct {
    Username string `json:"username"`
    jwt.StandardClaims
}

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

    r.POST("/login", login)
    r.GET("/protected", authenticateJWT(), protected)

    r.Run()
}

func login(c *gin.Context) {
    var creds struct {
        Username string `json:"username"`
        Password string `json:"password"`
    }

    if err := c.ShouldBindJSON(&creds); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
        return
    }

    if creds.Username == "admin" && creds.Password == "password123" {
        expirationTime := time.Now().Add(5 * time.Minute)
        claims := &Claims{
            Username: creds.Username,
            StandardClaims: jwt.StandardClaims{
                ExpiresAt: expirationTime.Unix(),
            },
        }

        token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        tokenString, err := token.SignedString(jwtKey)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
            return
        }

        c.JSON(http.StatusOK, gin.H{"token": tokenString})
    } else {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
    }
}

func authenticateJWT() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenString := c.GetHeader("Authorization")
        claims := &Claims{}

        token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
            return jwtKey, nil
        })

        if err != nil || !token.Valid {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            c.Abort()
            return
        }

        c.Set("username", claims.Username)
        c.Next()
    }
}

func protected(c *gin.Context) {
    username := c.MustGet("username").(string)
    c.JSON(http.StatusOK, gin.H{"message": "Welcome to the protected route!", "user": username})
}
  • r.GET("/protected", authenticateJWT(), protected):定义 GET 请求的路由/protected,这是受保护的路由,请求会先经过authenticateJWT中间件进行 JWT 验证,验证通过后再由protected函数处理。
  • login()方法首先定义一个匿名结构体creds用于接收客户端发送的 JSON 格式的用户名和密码。
  • c.ShouldBindJSON(&creds):尝试将客户端发送的 JSON 数据绑定到creds结构体上,如果绑定失败则返回 HTTP 400 错误。
  • 检查用户名和密码是否正确,如果正确则生成一个 JWT。
    • expirationTime:设置 JWT 的过期时间为当前时间加上 5 分钟。
    • claims:创建一个Claims结构体实例,包含用户名和过期时间。
    • jwt.NewWithClaims(jwt.SigningMethodHS256, claims):使用 HS256 算法创建一个新的 JWT。
    • token.SignedString(jwtKey):使用jwtKey对 JWT 进行签名,生成 JWT 字符串。
    • 如果签名成功,将 JWT 字符串作为响应返回给客户端;否则返回 HTTP 500 错误。
  • 如果用户名或密码不正确,返回 HTTP 401 错误。

授权技术

在这里插入图片描述

基于角色的访问控制

RBAC (Role-based access control)是一种基于角色的访问控制技术。这种方法可以有效地管理不同级别用户的权限。

示例:基于角色的访问控制

package main

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

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

    admin := r.Group("/admin", roleMiddleware("admin"))
    admin.GET("/dashboard", adminDashboard)

    r.Run()
}

func roleMiddleware(role string) gin.HandlerFunc {
    return func(c *gin.Context) {
        userRole := c.GetHeader("Role")
        if userRole != role {
            c.JSON(http.StatusForbidden, gin.H{"error": "Access forbidden"})
            c.Abort()
            return
        }
        c.Next()
    }
}

func adminDashboard(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"message": "Welcome to the admin dashboard!"})
}

在这个例子中,roleMiddleware 检查用户是否有合适的角色来访问路由。

授权的中间件

中间件功能可用于集中处理授权逻辑,从而更容易管理整个应用程序的访问控制。

示例:授权的中间件

package main

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

func main() {
    r := gin.Default()
    r.Use(authMiddleware)
    r.GET("/profile", userProfile)
    r.Run()
}

func authMiddleware(c *gin.Context) {
    token := c.GetHeader("Authorization")
    if token != "valid-token" {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
        c.Abort()
        return
    }
    c.Next()
}

func userProfile(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"message": "User profile"})
}

在本例中,authMiddleware检查请求是否为有效的授权 token。

应用程序安全

HTTPS设置

设置HTTPS对于通过加密客户机和服务器之间交换的数据来保护应用程序至关重要。

示例:HTTPS设置

要设置HTTPS,你需要有效的SSL证书。出于开发目的,可以使用自签名证书。

package main

import (
    "github.com/gin-gonic/gin"
    "log"
)

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

    // Your routes here

    // Replace with your certificate and key files
    err := r.RunTLS(":443", "server.crt", "server.key")
    if err != nil {
        log.Fatal("Failed to start server: ", err)
    }
}

在本例中,RunTLS方法使用提供的证书和密钥文件以HTTPS启动服务器。

预防常见安全漏洞

防止SQL注入

始终使用参数化查询或ORM库来防止SQL注入攻击。

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    r := gin.Default()
    db, err := sql.Open("mysql", "user:password@/dbname")
    if err != nil {
        panic(err)
    }

    r.GET("/user/:id", func(c *gin.Context) {
        id := c.Param("id")
        var name string
        err := db.QueryRow("SELECT name FROM users WHERE id = ?", id).Scan(&name)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "User not found"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"name": name})
    })

    r.Run()
}

在本例中,查询使用参数化语句来防止SQL注入。这里的 ? 是占位符,db.QueryRow 方法会先把 SQL 语句发送给数据库进行预编译,之后再把 id 作为参数传递给数据库。数据库会把参数当作普通的数据来处理,而不会将其作为 SQL 语句的一部分进行解析,这样就能有效防止恶意用户通过构造特殊输入来改变 SQL 语句的逻辑,进而避免 SQL 注入。

如果代码没有使用预编译语句,而是直接把用户输入拼接到 SQL 语句中,例如:

query := "SELECT name FROM users WHERE id = " + id
err := db.QueryRow(query).Scan(&name)

这种情况下,若恶意用户将 id 设置为特殊的值,如 1 OR 1=1,那么拼接后的 SQL 语句就会变成 SELECT name FROM users WHERE id = 1 OR 1=1,这样会使查询条件恒为真,从而可能导致数据库中的敏感信息被泄露,这就是 SQL 注入的危害。

防止跨站脚本(XSS)

清除任何用户输入以防止XSS攻击。使用像“blumonday”这样的库来清理HTML输入。

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/microcosm-cc/bluemonday"
)

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

    r.POST("/comment", func(c *gin.Context) {
        comment := c.PostForm("comment")
        policy := bluemonday.UGCPolicy()
        sanitizedComment := policy.Sanitize(comment)
        c.JSON(200, gin.H{"comment": sanitizedComment})
    })

    r.Run()
}

在本例中,用户输入在使用之前被清理。

最后总结

通过遵循本章概述的实践,你可以在Gin应用程序中实现健壮的身份验证和授权机制,确保它们是安全可靠的。Gin,愈学习愈快乐, Go!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/961300.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 中用于控制输出格式的操纵符——setw 、setfill、setprecision、fixed

目录 四种操纵符简要介绍 setprecision基本用法 setfill的基本用法 fixed的基本用法 setw基本用法 以下是一些常见的用法和示例: 1. 设置字段宽度和填充字符 2. 设置字段宽度和对齐方式 3. 设置字段宽度和精度 4. 设置字段宽度和填充字符,结合…

06_改善播放效果--优先级与阻塞

一、声明 本文章的程序是基于05篇的程序改善的,所以CubeMx的配置看05篇的就好 且此篇文章由于红外遥控暂时未使用,还不知其是否能成功显示现象 二、keil5代码 这个优先级要1,但是如果只是这个优先级1的话,那么我的LED灯闪烁的任务…

【Rust自学】16.3. 共享状态的并发

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 16.3.1. 使用共享来实现并发 还记得Go语言有一句名言是这么说的:Do not commun…

项目集成Nacos

文章目录 1.环境搭建1.创建模块 sunrays-common-cloud-nacos-starter2.目录结构3.pom.xml4.自动配置1.NacosAutoConfiguration.java2.spring.factories 5.引入cloud模块通用依赖 2.测试1.创建模块 sunrays-common-cloud-nacos-starter-demo2.目录结构3.pom.xml4.application.ym…

计算机网络 (59)无线个人区域网WPAN

前言 无线个人区域网(WPAN,Wireless Personal Area Network)是一种以个人为中心,采用无线连接方式的个人局域网。 一、定义与特点 定义:WPAN是以个人为中心,实现活动半径小、业务类型丰富、面向特定群体的无…

Python 之 Excel 表格常用操作

示例文件 test.xlsx 将各个表单拆分成单独的 Excel 文件 import os.pathimport openpyxl import pandasdef handle_excel(file_path):dirname os.path.dirname(file_path)basename os.path.basename(file_path).split(".")[0]wb openpyxl.load_workbook(file_pat…

01学习预热篇(D6_正式踏入JVM深入学习前的铺垫)

目录 学习前言 一、虚拟机的结构 1. Java虚拟机参数设置 2. java 堆 3. 出入栈 4. 局部变量表 1> 局部变量的剖析 2> 局部变量的回收 5. 操作数栈 1> 常量入栈指令 2> 局部变量值转载到栈中指令 3> 将栈顶值保存到局部变量中指令 6. 帧数据区 7. 栈…

知识库建设对提升团队协作与创新能力的影响分析

内容概要 在当今快速变革的商业环境中,知识库建设的重要性愈发凸显。它不仅是信息存储的载体,更是推动组织内部沟通与协作的基石。通过系统整理与管理企业知识,团队成员能够便捷地访问相关信息,使得协作过程更为流畅,…

C语言字符串详解

1. C语言中的字符串基础 C语言中的字符串是程序设计中不可忽视的部分。与现代高级编程语言不同,C语言对字符串的处理方式直接、灵活,并且强大。在C语言中,字符串并不是一种特殊的数据类型,而是字符数组的一种表现形式。字符串通常…

神经网络的通俗介绍

人工神经网络,是一种模仿人类大脑工作原理的数学模型。人类的大脑是由无数的小“工作站”组成的,每个工作站叫做“神经元”。这些神经元通过“电线”互相连接,负责接收、处理和传递信息。 一、人类大脑神经网络 人类大脑的神经网络大概长这…

SpringBoot中Excel表的导入、导出功能的实现

文章目录 一、easyExcel简介二、Excel表的导出2.1 添加 Maven 依赖2.2 创建导出数据的实体类4. 编写导出接口5. 前端代码6. 实现效果 三、excel表的导出1. Excel表导入的整体流程1.1 配置文件存储路径 2. 前端实现2.1 文件上传组件 2.2 文件上传逻辑3. 后端实现3.1 文件上传接口…

vim交换文件的工作原理

在vim中,交换文件是一个临时文件,当我们使用vim打开一个文件进行编辑(一定得是做出了修改才会产生交换文件)时候,vim就会自动创建一个交换文件,而之后我们对于文件的一系列修改都是在交换文件中进行的&…

C++/stack_queue

目录 1.stack 1.1stack的介绍 1.2stack的使用 练习题: 1.3stack的模拟实现 2.queue的介绍和使用 2.1queue的介绍 2.2queue的使用 2.3queue的模拟实现 3.priority_queue的介绍和使用 3.1priority_queue的介绍 3.2priority_queue的使用 欢迎 1.stack 1.1stack…

5分钟带你获取deepseek api并搭建简易问答应用

目录 1、获取api 2、获取base_url和chat_model 3、配置模型参数 方法一:终端中临时将加入 方法二:创建.env文件 4、 配置client 5、利用deepseek大模型实现简易问答 deepseek-v3是截止博文撰写之日,无论是国内还是国际上发布的大模型中…

机器学习day4

自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测 import numpy as np import torch import torch.nn as nn import torch.optim as optimizer import matplotlib.pyplot as pltclass1_points np.array([[2.1, 1.8],[1.9, 2…

58.界面参数传递给Command C#例子 WPF例子

界面参数的传递,界面参数是如何从前台传送到后台的。 param 参数是从界面传递到命令的。这个过程通常涉及以下几个步骤: 数据绑定:界面元素(如按钮)的 Command 属性绑定到视图模型中的 RelayCommand 实例。同时&#x…

Julius AI 人工智能数据分析工具介绍

Julius AI 是一款由 Casera Labs 开发的人工智能数据分析工具,旨在通过自然语言交互和强大的算法能力,帮助用户快速分析和可视化复杂数据。这款工具特别适合没有数据科学背景的用户,使数据分析变得简单高效。 核心功能 自然语言交互&#x…

【JavaEE进阶】应用分层

目录 🎋序言 🍃什么是应用分层 🎍为什么需要应用分层 🍀如何分层(三层架构) 🎄MVC和三层架构的区别和联系 🌳什么是高内聚低耦合 🎋序言 通过上⾯的练习,我们学习了SpringMVC简单功能的开…

在 Ubuntu22.04 上安装 Splunk

ELK感觉太麻烦了,换个日志收集工具 Splunk 是一种 IT 工具,可帮助在任何设备上收集日志、分析、可视化、审计和创建报告。简单来说,它将“机器生成的数据转换为人类可读的数据”。它支持从虚拟机、网络设备、防火墙、基于 Unix 和基于 Windo…

ES设置证书和创建用户,kibana连接es

1、启动好es 2、进入es容器 docker exec -it es /bin/bash 3、生成ca证书 ./bin/elasticsearch-certutil ca 注:两个红方框位置直接回车 4、生成cert证书 ./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 注:前两个红框直接回车&am…