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框架 -- 中间件

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

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

相关文章

SIEMENS S7-1200 汽车转弯灯程序 编程与分析

公告 项目地址:https://github.com/MartinxMax/SIEMENS-1200-car_turn_signal 分析 题目: 画IO分配表 输入输出m3.0左转弯开关q0.0左闪灯m3.1右转弯开关q0.1右闪灯m3.2停止开关 博图V16配置 设置PLC的IP地址 允许远程通信访问 将HMI设备拖入 注意,我们这边选择的是HMI连接…

数据结构----算法--五大基本算法(这里没有写分支限界法)和银行家算法

数据结构----算法–五大基本算法(这里没有写分支限界法)和银行家算法 一.贪心算法 1.什么是贪心算法 在有多个选择的时候不考虑长远的情况,只考虑眼前的这一步,在眼前这一步选择当前的最好的方案 二.分治法 1.分治的概念 分…

【JavaEE】Callable 接口

Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的方式计算结果. 实现Callable也是创建线程的一种方法!!!! Callable的用法非常接近于Runnable,Runnable描述了一个任务&#…

Mysql创建视图中文乱码修改docker里的配置

问题现象: 创建的视图查询无数据,查看创建语句得知,where条件里的中文变成了“???”。 在客户端里查询字符编码: show VARIABLES like %char%;就是character_set_server导致的,它配置的竟然不是utf8,…

通过SVN拉取项目 步骤

方法一:文件夹方式 首先新建一个空的文件夹,例如,名为“demo”的空文件夹 在这个空的文件夹中鼠标右键,点击SVN Checkout 会出现下图所示的页面,第一个输入框是svn的项目地址,第二个输入框是拉取项目所放的…

OpenGL —— 2.6、绘制一个正方体并贴图(附源码,glfw+glad)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库,该库只有一个头文件。 具体代码: vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _viewMatrix; u…

docker 安装 sftpgo

sftpgo 简介 sftpgo 是一个功能齐全且高度可配置的 SFTP 服务器,具有可选的 HTTP/S、FTP/S 和 WebDAV 支持。支持多种存储后端:本地文件系统、加密本地文件系统、S3(兼容)对象存储、Google 云存储、Azure Blob 存储、SFTP。 官…

关于Git的入门教程(附GitHub和Gitee的使用方法)

一. Git 概述 Git是一个免费的、开源的分布式版本控制系统,可以快速高效地处理从小型到大型的各种项目。Git易于学习、占地面积小、性能极快。它具有廉价的本地库,方便的暂存区域和多个工作流分支等特性。其性能优于Subversion、CVS、Perforce和ClearCas…

SpringMVC之全局异常拦截器

在SpringMVC自动装配核心类之WebMvcAutoConfiguration内部实例化EnableWebMvcConfiguration过程中会触发其父类WebMvcConfigurationSupport内部初始化HandlerExceptionResolver。 1.WebMvcConfigurationSupport public class WebMvcConfigurationSupport implements Applicat…

2434: 【区赛】[慈溪2013]统计方格

题目描述 给出一张 n 行 m 列仅由黑白方格组成的黑白图片(行从上到下 1 到 n 编号,列从左到右 1 到 m 编号)。如下图是一张由 17 行 18 列方格构成的黑白图片,图片中的任意一个方格要么是白色,要么是黑色。 仔细观察这…

Python —— UI自动化之Page Object模式

1、Page Object模式简介 1、二层模型 Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试广泛使用的一种分层设计 模式。核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层操作组装业务逻辑。 1、实战 …

springBoot--web--函数式web

函数式web 前言场景给容器中放一个Bean&#xff1a;类型是 RouterFunction<ServerResponse>每个业务准备一个自己的handler使用集合的时候加注解请求的效果 前言 springmvc5.2 以后允许我们使用函数式的方式&#xff0c;定义web的请求处理流程 函数式接口 web请求处理的…

【Dockerfile镜像实战】构建LNMP环境并运行Wordpress网站平台

这里写目录标题 一、项目背景和要求二、项目环境三、部署过程1&#xff09;创建自定义网络2&#xff09;部署NginxStep1 创建工作目录并上传相关软件包Step2 编写Dockerfile文件Step3 编写配置文件nginx.confStep4 创建nginx镜像Step5 运行容器 3&#xff09;部署MysqlStep1 创…

Spring Cloud Alibaba Seata 实现分布式事物

Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;为用户打造一站式的分布式解决方案 Seata 官网&#xff1a;https://seata.io/zh-cn/ Spring Cloud Alibaba 官…

Leetcode—2652.倍数求和【简单】

2023每日刷题&#xff08;四&#xff09; Leetcode—2652.倍数求和 实现代码 int sumOfMultiples(int n){int ans 0;int i 1;for(; i < n; i) {if((i % 3 0) || (i % 5 0) || (i % 7 0)) {ans i;}}return ans; }测试结果 之后我会持续更新&#xff0c;如果喜欢我的文…

STM32,我想看单片机上的外设时钟,我怎么看?

一&#xff1a;在工程中加入rcc文件 首先需要加载我们的时钟函数的文件 stm32f10x_rcc.h 和 stm32f10x_rcc.c 文件 二&#xff1a;查看文件 在h头文件 尾部&#xff0c;有我们这个总线的函数 在函数体内&#xff0c;有我们这个宏定义的 外设时钟&#xff0c;我们拿就行了 APB2_…

MapReduce编程:join操作和聚合操作

文章目录 MapReduce 编程&#xff1a;join操作和聚合操作一、实验目标二、实验要求及注意事项三、实验内容及步骤 附&#xff1a;系列文章 MapReduce 编程&#xff1a;join操作和聚合操作 一、实验目标 理解MapReduce计算框架的分布式处理工作流程掌握用mapreduce计算框架实现…

Git Bash(一)Windows下安装及使用

目录 一、简介1.1 什么是Git&#xff1f;1.2 Git 的主要特点1.3 什么是 Git Bash&#xff1f; 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置&#xff08;【Next】 即可&#xff09;3.4 安装完毕3.5 打开 Git Bash 官网地址&#xff1a; https://www.git-scm.com/…

codeforces (C++ Morning)

题目&#xff1a; 翻译&#xff1a; 思路&#xff1a; 1、要将四位数显示&#xff0c;每次操作可以选择移动光标&#xff08;移动到相邻的位置&#xff09;或者显示数字&#xff0c;计算最少需要多少次操作。 2、用flag表示当前光标位置&#xff0c;sum为记录操作次数&#…

开源软件-禅道Zentao

禅道Zentao 简介漏洞复现SQL注入漏洞**16.5****router.class.php SQL注入** **v18.0-v18.3****后台命令执行** 远程命令执行漏洞&#xff08;RCE&#xff09;后台命令执行 简介 是一款开源的项目管理软件&#xff0c;旨在帮助团队组织和管理他们的项目。Zentao提供了丰富的功能…