当前位置: 首页 > news >正文

gin框架39--重构 BasicAuth 中间件

gin框架39--重构 BasicAuth 中间件

  • 介绍
  • gin BasicAuth 解析
  • 自定义newAuth实现基础认证
  • 注意事项
  • 说明

介绍

每当我们打开一个网址的时候,会自动弹出一个认证界面,要求我们输入用户名和密码,这种BasicAuth是最基础、最常见的认证方式,gin框架中提供了一种内置的方式,但它只能用内置的用户和密码,无法使用外部db中的用户和密码,这种方式很多时候是不友好的。
为此,本文根据gin.BasicAuth的原理对其就行重构,实现一个简单的newAuth中间件,该中间件可以代替默认的BasicAuth,并且可以按需更改为自定义查询函数,实现从外部db或者用户管理系统查询信息实现登录认证的功能。

gin BasicAuth 解析

博文 gin框架14–使用 BasicAuth 中间件 介绍了BasicAuth 中间件的基础使用方法,直接使用 gin.BasicAuth(gin.Accounts{“foo”: “bar”, “austin”: “1234”, “lena”: “hello2”, “manu”: “4321”, }) 即可,非常简单实用。

实际上当我们访问url的时候,它会从请求的 Authorization 中获取用户信息,并和gin.Accounts中内置用户对比,如果用户存在就将用户名称存放在Context的 Keys map结构中,方便后续查找或者获取用户信息;如果不存在就设置c.Header(“WWW-Authenticate”, realm), 并返回c.AbortWithStatus(http.StatusUnauthorized),浏览器上的表现就是重新弹出输入用户名和密码的窗口 。

核心逻辑在 BasicAuthForRealm 方法中,如下所示:

func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {if realm == "" {realm = "Authorization Required"}realm = "Basic realm=" + strconv.Quote(realm)pairs := processAccounts(accounts)return func(c *Context) {// Search user in the slice of allowed credentialsuser, found := pairs.searchCredential(c.requestHeader("Authorization"))if !found {// Credentials doesn't match, we return 401 and abort handlers chain.c.Header("WWW-Authenticate", realm)c.AbortWithStatus(http.StatusUnauthorized)return}// The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using// c.MustGet(gin.AuthUserKey).c.Set(AuthUserKey, user)}
}

自定义newAuth实现基础认证

gin.BasicAuth 只能提供默认的认证功能,且需要内置指定的用户|密码,但实际在代码中hardcode大量用户信息是不科学的,因此我们需要自己重构一个BasicAuth来实验基础认证功能。
此处实现了一个newAuth中间件,该中间件会判断用户是否输入账号|密码,并通过judgeUserExist来判断账号|密码是否正确,正确则返回用户信息,不正确则返回http.StatusUnauthorized, 具体案例如下。

此处为了简洁方便,此处直接内置了3个用户到users中,并用 judgeUserExist 查询用户账号密码是否正确。实际项目中可将该方法更改为查询db,无需在项目中hardcode内置用户。

package mainimport ("encoding/base64""fmt""github.com/gin-gonic/gin""net/http""strconv""strings"
)var users = gin.H{"foo":    gin.H{"email": "foo@bar.com", "phone": "123433", "pwd": "bar"},"austin": gin.H{"email": "austin@example.com", "phone": "666", "pwd": "123"},"lena":   gin.H{"email": "lena@guapa.com", "phone": "523443", "pwd": "456"},
}func help() string {helpStr := `hello gin:
127.0.0.1:8088/your-api
/auth/user
`return helpStr
}func judgeUserExist(userName, userPwd string) (string, bool) {// 实际项目中将该函数更改为从db查询即可,此处为了简单直接从预定的users中查询。msg := ""tag := falseif userInfo, ok := users[userName]; ok {pwd, ok := userInfo.(gin.H)["pwd"]if ok && pwd == userPwd {msg = fmt.Sprintf("用户%v密码正确", userName)tag = true} else {msg = fmt.Sprintf("用户%v密码不正确", userName)}} else {msg = fmt.Sprintf("用户%v不存在", userName)}return msg, tag
}func getUserPwdFromAuthorization(auth string) (user, pwd string) {// auth[:6]="Basic "base64UserPwd, err := base64.StdEncoding.DecodeString(auth[6:])if err != nil {panic(err)}base64UserPwdStr := string(base64UserPwd)colonIndex := strings.Index(base64UserPwdStr, ":")user = base64UserPwdStr[:colonIndex]pwd = base64UserPwdStr[colonIndex+1:]return user, pwd
}func newAuth(realm string) func(c *gin.Context) {if realm == "" {realm = "Authorization Required"}realm = "Basic realm=" + strconv.Quote(realm)return func(c *gin.Context) {authHeader := c.Request.Header.Get("Authorization") // 获取请求头中的数据if authHeader == "" {c.Header("WWW-Authenticate", realm)c.AbortWithStatus(http.StatusUnauthorized)return} else {user, pwd := getUserPwdFromAuthorization(authHeader)// fmt.Printf("user=%v,pwd=%v\n", user, pwd)msg, tag := judgeUserExist(user, pwd)if !tag {// c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": msg, "tag": tag})fmt.Println(msg)c.AbortWithStatus(http.StatusUnauthorized)return}c.Set(gin.AuthUserKey, user)}}
}func userHandler(c *gin.Context) {user := c.MustGet(gin.AuthUserKey).(string)c.IndentedJSON(http.StatusOK, gin.H{"status":   200,"msg":      "it's fine","userInfo": users[user],})
}func main() {app := gin.Default()app.GET("/", func(c *gin.Context) {c.String(http.StatusOK, help())})authorized := app.Group("/auth", newAuth(""))authorized.GET("/user", userHandler)app.Run(":8088")
}

输出:
在这里插入图片描述

注意事项

  1. c.Header中需要添加 WWW-Authenticate 字段,否则初次访问的时候不会弹出输入用户名、密码的框!!!

说明

  1. 测试环境
    ubuntu22.04 Desktop
    go1.20.7
  2. 参考文档
    using-basicauth-middleware
    Gin框架 -- 中间件

相关文章:

gin框架39--重构 BasicAuth 中间件

gin框架39--重构 BasicAuth 中间件 介绍gin BasicAuth 解析自定义newAuth实现基础认证注意事项说明 介绍 每当我们打开一个网址的时候,会自动弹出一个认证界面,要求我们输入用户名和密码,这种BasicAuth是最基础、最常见的认证方式&#xff0…...

编译pycaffe过程中遇到的问题及解决

pycaffe是python调用caffe的方式,编译它就是要得到一个so库_pycaffe.so。 如题,在caffe的源码目录下,执行make pycaffe,跳出来一个错误: $ make pycaffe CXX/LD -o python/caffe/_caffe.so python/caffe/_caffe.cpp /usr/bin/ld…...

自然语言处理---Transformer机制详解之Transformer优势

1 Transformer的并行计算 对于Transformer比传统序列模型RNN/LSTM具备优势的第一大原因就是强大的并行计算能力. 对于RNN来说,任意时刻t的输入是时刻t的输入x(t)和上一时刻的隐藏层输出h(t-1),经过运算后得到当前时刻隐藏层的输出h(t),这个…...

改进YOLO系列 | YOLOv5/v7 引入 Dynamic Snake Convolution | 动态蛇形卷积

准确分割拓扑管状结构,如血管和道路,在各个领域中至关重要,可以确保下游任务的准确性和效率。然而,许多因素使任务复杂化,包括细小的局部结构和可变的全局形态。在这项工作中,我们注意到管状结构的特殊性,并利用这一知识来引导我们的DSCNet,以在三个阶段同时增强感知:…...

postgresql14-表的管理(四)

表table 创建表 CREATE TABLE table_name --表名 (column_name data_type column_constraint, --字段名、字段类型、约束字段(可选)column_name data_type, --表级别约束字段...,table_constraint );CREATE TABLE emp1 --创建表 AS SELECT * FROM empl…...

Java--Object类

Java中Object类是所有类的父类,是Java中最高层的类。用户创建一个类时,除非指定继承了某个类,否则都是继承于Object类。 由于所有类都继承于Object类,所以所有类都可以重写Object类中的方法。但是Object类中被final修饰的getClass…...

交换机端口灯常亮 端口up状态 服务器设置ip交换机获取不到服务器网卡mac地址 不能通信

环境: 深信服防火墙 8.0.75 AF-2000-FH2130B-SC S6520X-24ST-SI交换机 version 7.1.070, Release 6530P02 问题描述: 交换机一个vlan下有3台服务器,连接端口2、3、4,2和3连接的服务器正常,交换机3端口灯常亮 端口up状态 服务器自动获取不了地址,改为手动设置ip后,交…...

Linux笔记之diff和vimdiff

Linux笔记之diff和vimdiff code review! 文章目录 Linux笔记之diff和vimdiff一.diff1.1.使用diff比较文件夹1.2.使用diff比较文件1.4.colordiff——带颜色输出差异 二.vimdiff2.1.vimdiff颜色差异2.2.vimfiff调整栏宽2.3.修改颜色变谈,使代码可以看清楚2.4.vimdif…...

目标检测YOLO实战应用案例100讲-基于改进的YOLOV5算法的垃圾分类模型

目录 前言 国内外研究现状 目标检测算法发展现状 YOLO算法的发展现状...

我做不到受每个人喜欢

我做不到受每个人喜欢 我想描述一下昨天发生争吵后我个人的观点,希望能够重新呈现出一种积极的态度。 首先,让我简要梳理一下事件的经过,当天我像往常一样去另一个宿舍找人聊天,可能因为说话声音有点大,坐在我后面的那…...

Linux笔记之diff工具软件P4merge的使用

Linux笔记之diff工具软件P4merge的使用 code review! 文章目录 Linux笔记之diff工具软件P4merge的使用1.安装和配置2.使用:p4merge a.cc b.cc3.配置git 参考博文: Ubuntu Git可视化比较工具 P4Merge 的安装/配置及使用 1.安装和配置 $ wget https://cdist2.per…...

使用 OpenSSL 扩展来实现公钥和私钥加密

首先,你需要生成一对公钥和私钥。可以使用 OpenSSL 工具来生成: 1、生成私钥 openssl genpkey -algorithm RSA -out private_key.pem 2、从私钥生成公钥: openssl rsa -pubout -in private_key.pem -out public_key.pem现在你有了一个私钥…...

二、安全与风险管理—安全与风险管理基础

目录 目录 1.什么是信息与信息的生命周期 2.信息安全的基本目标 3.风险管理与控制类型...

rust学习——栈、堆、所有权

文章目录 栈、堆、所有权栈(Stack)与堆(Heap)栈堆性能区别所有权与堆栈 所有权原则变量作用域所有权与函数返回值与作用域 栈、堆、所有权 栈(Stack)与堆(Heap) 栈和堆是编程语言最核心的数据结构,但是在很多语言中,你并不需要深入了解栈与堆。 但对于…...

如何从小白成长为AI工程师笔记

📚入门机器学习基础 对于本科生来说,需要打好数学基础,包括高数、概率论和线性代数。 对于已经上研究生或工作想转行的人来说,可以直接开始学习机器学习算法,重要的是理解算法的原理和推导过程。如果有时间和需要&am…...

fail-fast 和 fail-safe 迭代器

fail-fast 和 fail-safe 迭代器是两种不同的迭代器设计策略,用于在遍历集合(如 ArrayList、HashMap)时处理并发修改的情况。它们的行为和应对策略有所不同: Fail-Fast 迭代器: Fail-Fast 迭代器在遍历集合期间&#x…...

Nvidia显卡基础概念介绍

一、PCIe与SXM 1.1 Nvidia GPU PCIe PCIe(peripheral component interconnect express)是一种高速串行计算机扩展总线标准,是英特尔公司在2001年提出来的,它的出现主要是为了取代AGP接口,优点就是兼容性比较好,数据传输速率高、…...

使用screen实现服务器代码一直运行

1.安装screen sudo apt install screen 2.创建一个screen(创建一个名为chatglm的新的链接,用来一直运行 screen -S chatglm 3.查看进程列表 screen -ls 创建之后,就可以在当前窗口利用cd命令进入要执行的项目中,开始执行&#xf…...

Linux系统自有服务

一、Linux中防火墙firewalld 1、什么是防火墙 防火墙:防范一些网络攻击。有软件防火墙、硬件防火墙之分。 防火墙选择让正常请求通过,从而保证网络安全性。 Windows防火墙: Windows防火墙的划分与开启、关闭操作: 2、防火墙的作…...

Andriod学习笔记(二)

页面设计的零碎知识 通用属性设置文本大小设置视图宽高设置视图的对齐方式 页面布局LinearLayoutRelativeLayoutGridLayoutScollView 按钮触控ButtonImageViewImageButton 通用属性 设置文本大小 纯数字的setTextSize方法,内部默认字体单位为sp,sp是An…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes&#xff0…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如&#xff1a…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...