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

news2025/4/21 7:45:27

在本章中,我们将探讨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!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CVE-2025-0411 7-zip 漏洞复现

文章目录 免责申明漏洞描述影响版本漏洞poc漏洞复现修复建议 免责申明 本文章仅供学习与交流,请勿用于非法用途,均由使用者本人负责,文章作者不为此承担任何责任 漏洞描述 此漏洞 (CVSS SCORE 7.0) 允许远程攻击者绕…

学习数据结构(1)时间复杂度

1.数据结构和算法 (1)数据结构是计算机存储、组织数据的方式,指相互之间存在⼀种或多种特定关系的数据元素的集合 (2)算法就是定义良好的计算过程,取一个或一组的值为输入,并产生出一个或一组…

算法每日双题精讲 —— 二分查找(寻找旋转排序数组中的最小值,点名)

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟 别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧💪 在算法的…

STM32-时钟树

STM32-时钟树 时钟 时钟

算法知识补充2

一部分&#xff1a;Tire树&#xff1a;高效地存储和查找字符串集合的数据结构acwing835 #include<iostream> #include<cstring> using namespace std; const int N100010; int son[N][26],cnt[N],idx; char str[N]; void insert(char str[]){int p0;for(int i0;st…

微信小程序-点餐(美食屋)02开发实践

目录 概要 整体架构流程 &#xff08;一&#xff09;用户注册与登录 &#xff08;二&#xff09;菜品浏览与点餐 &#xff08;三&#xff09;订单管理 &#xff08;四&#xff09;后台管理 部分代码展示 1.index.wxml 2.list.wxml 3.checkout.wxml 4.detail.wxml 小结优点 概要…

WPF基础 | WPF 常用控件实战:Button、TextBox 等的基础应用

WPF基础 | WPF 常用控件实战&#xff1a;Button、TextBox 等的基础应用 一、前言二、Button 控件基础2.1 Button 的基本定义与显示2.2 按钮样式设置2.3 按钮大小与布局 三、Button 的交互功能3.1 点击事件处理3.2 鼠标悬停与离开效果3.3 按钮禁用与启用 四、TextBox 控件基础4.…

CentOS7使用源码安装PHP8教程整理

CentOS7使用源码安装PHP8教程整理 下载安装包解压下载的php tar源码包安装所需的一些依赖扩展库安装前的配置修改配置文件1、进入php8的安装包 配置环境变量开机自启启动服务创建软连接常见问题1、checking for icu-uc > 50.1 icu-io icu-i18n... no2、configure: error: Pa…

08-Elasticsearch

黑马商城作为一个电商项目&#xff0c;商品的搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的&#xff0c;存在很多问题。 首先&#xff0c;查询效率较低。 由于数据库模糊查询不走索引&#xff0c;在数据量较大的时候&#xff0c;查询性能很…

SQL在DBA手里-改写篇

背景 最近运营需要做月报汇总交易情况&#xff0c;之前一直是他们手工出的数据&#xff0c;他们想做成月初自动发送邮件&#xff0c;从而减轻他们的工作量。于是他们提供SQL我们在邮件服务器配置做定时发送任务。 表介绍&#xff08;表及字段已做脱敏处理&#xff09; trans…

企业财务管理系统的需求设计和实现

该作者的原创文章目录&#xff1a; 生产制造执行MES系统的需求设计和实现 企业后勤管理系统的需求设计和实现 行政办公管理系统的需求设计和实现 人力资源管理HR系统的需求设计和实现 企业财务管理系统的需求设计和实现 董事会办公管理系统的需求设计和实现 公司组织架构…

Couchbase UI: Server

在 Couchbase UI 中的 Server&#xff08;服务器&#xff09;标签页主要用于管理和监控集群中的各个节点。以下是 Server 标签页的主要内容和功能介绍&#xff1a; 1. 节点列表 显示集群中所有节点的列表&#xff0c;每个节点的详细信息包括&#xff1a; 节点地址&#xff1…

【软件设计师中级】-笔记缩减版本-计算机系统基础知识

1. 计算机系统基础知识 1.1. 计算机系统硬件基本组成硬件 中央处理器&#xff08;CPU&#xff09;硬件系统的核心 运算器 控制器 存储器&#xff08;记忆设备&#xff09; 内部存储器&#xff08;速度高&#xff0c;容量小&#xff09;&#xff1a;临时存放程序、数据及中间结…

SAP MM 记录一次SAP外协采购收货提示 这种物料的特殊库存 O 0100003359 14019002不存在的问题

根据采购订单收货&#xff0c;调用时 BAPI_GOODSMVT_CREATE时返回 { "TYPE":"E", "ID":"M7", "NUMBER":"076", "MESSAGE":"这种物料的特殊库存 O 0100003359 14019002不存在"…

在 Ubuntu22.04 上安装 Splunk

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

计算机网络 (60)蜂窝移动通信网

一、定义与原理 蜂窝移动通信网是指将一个服务区分为若干蜂窝状相邻小区并采用频率空间复用技术的移动通信网。其原理在于&#xff0c;将移动通信服务区划分成许多以正六边形为基本几何图形的覆盖区域&#xff0c;称为蜂窝小区。每个小区设置一个基站&#xff0c;负责本小区内移…

壁纸设计过程中如何增加氛围感

在壁纸设计过程中&#xff0c;增加氛围感是提升整体视觉效果和情感传达的关键。以下是一些具体的方法和技巧&#xff0c;帮助你在设计中营造出强烈的氛围感&#xff1a; 一、色彩运用 选择主题色&#xff1a; 根据你想要传达的情感选择主色调。例如&#xff0c;温暖的色调&…

|Python新手小白中级教程|第二十九章:面向对象编程(Python类的拓展延伸与10道实操题目)(5)

文章目录 前言1.类变量与实例变量2.静态方法和类方法1.静态方法2.类方法 3.实操使用1. 创建一个名为Person的类&#xff0c;包含属性name和age&#xff0c;并且有一个方法introduce()用于介绍自己的名字和年龄。2. 创建一个名为Circle的类&#xff0c;包含属性radius和color&am…

UE求职Demo开发日志#12 完善击杀获得物品逻辑和UI

1 实现思路 1.给WarehouseManager添加一个按TArray增加物品的函数 2.Enemy身上一个变量记录掉落物品&#xff0c;死亡时调用增加物品函数 3.同时调用UI显示 2 实现过程 2.1 在WarehouseManager里添加一个AddItemByArray函数 遍历数组调用添加函数 void UWarehouseManage…

安装Ubuntu22.04

1.引用教程 如何安装Ubuntu Server 22.04 LTS_ubuntu22.04 server-CSDN博客 2.空间分配 要使用 docker 比较多所以分别的 docker 空间大