Gin框架操作指南08:日志与安全

官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/
注:本教程采用工作区机制,所以一个项目下载了Gin框架,其余项目就无需重复下载,想了解的读者可阅读第一节:Gin操作指南:开山篇。
本节演示日志与安全相关的API,包括定义路由日志的格式;如何记录日志;安全页眉;使用BasicAuth中间件;使用HTTP方法。其中控制日志输出颜色就是将gin.DisableConsoleColor()替换为gin.ForceConsoleColor(),读者可自行尝试,本文不做演示。在开始之前,我们需要在”04日志与安全“目录下打开命令行,执行如下命令来创建子目录:

mkdir 定义路由日志的格式 如何记录日志 安全页眉 使用BasicAuth中间件 使用HTTP方法

目录

    • 一、定义路由日志的格式
    • 二、如何记录日志
    • 三、安全页眉
    • 四、使用BasicAuth中间件
    • 五、使用HTTP方法

一、定义路由日志的格式

默认的路由日志格式:

[GIN-debug] POST   /foo                      --> main.main.func1 (3 handlers)
[GIN-debug] GET    /bar                      --> main.main.func2 (3 handlers)
[GIN-debug] GET    /status                   --> main.main.func3 (3 handlers)

如果你想要以指定的格式(例如 JSON,key values 或其他格式)记录信息,则可以使用 gin.DebugPrintRouteFunc 指定格式。 在下面的示例中,我们使用标准日志包记录所有路由,但你可以使用其他满足你需求的日志工具。

package mainimport ("log"      // 导入标准日志包,用于记录日志信息"net/http" // 导入 net/http 包,用于 HTTP 状态码和相关类型"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {r := gin.Default() // 创建一个默认的 Gin 路由引擎// 自定义路由打印函数,以指定的格式记录路由信息gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {// 使用标准日志包打印每个路由的 HTTP 方法、绝对路径、处理函数名称和处理函数数量log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)}// 定义 POST 路由 /foor.POST("/foo", func(c *gin.Context) {// 返回 JSON 响应,内容为 "foo" 和 HTTP 状态码 200c.JSON(http.StatusOK, "foo")})// 定义 GET 路由 /barr.GET("/bar", func(c *gin.Context) {// 返回 JSON 响应,内容为 "bar" 和 HTTP 状态码 200c.JSON(http.StatusOK, "bar")})// 定义 GET 路由 /statusr.GET("/status", func(c *gin.Context) {// 返回 JSON 响应,内容为 "ok" 和 HTTP 状态码 200c.JSON(http.StatusOK, "ok")})// 监听并在 0.0.0.0:8080 上启动服务r.Run() // 启动 Gin 路由引擎
}

效果
GET测试
在这里插入图片描述

POST测试
在这里插入图片描述

二、如何记录日志

package mainimport ("io" // 导入 io 包,用于多路写入"os" // 导入 os 包,用于文件操作"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 禁用控制台颜色,将日志写入文件时不需要控制台颜色。gin.DisableConsoleColor()// 创建一个文件用于保存日志,文件名为 "gin.log"f, err := os.Create("gin.log")if err != nil {panic(err) // 如果文件创建失败,抛出错误}// 设置 Gin 的默认写入器,将日志写入到刚创建的文件中gin.DefaultWriter = io.MultiWriter(f)// 如果需要同时将日志写入文件和控制台,请使用以下代码。// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)// 创建默认的 Gin 路由引擎router := gin.Default()// 定义 GET 路由 /pingrouter.GET("/ping", func(c *gin.Context) {// 返回字符串 "pong" 和 HTTP 状态码 200c.String(200, "pong")})// 监听并在 0.0.0.0:8080 上启动服务router.Run(":8080") // 启动 Gin 路由引擎
}

效果
注意,启动后控制台是没有输出的,因为屏蔽了颜色,但go.mod旁边会出现gin.log文件,打开即可看到控制台的输出
在这里插入图片描述
打开浏览器,测试,log文件会变化
在这里插入图片描述

三、安全页眉

使用安全标头保护网络应用程序免受常见安全漏洞的攻击非常重要。本示例将向您展示如何在 Gin 应用程序中添加安全标头,以及如何避免与主机标头注入相关的攻击(SSRF、开放重定向)。

package mainimport ("net/http" // 导入 net/http 包,用于 HTTP 相关的功能"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 创建一个默认的 Gin 路由引擎r := gin.Default()// 设置期望的主机头部(Host Header)expectedHost := "localhost:8080"// 设置安全标头的中间件r.Use(func(c *gin.Context) {// 检查请求中的 Host 是否符合预期if c.Request.Host != expectedHost {// 如果 Host 不正确,返回 400 错误并结束请求c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"})return}// 设置安全标头以保护应用程序c.Header("X-Frame-Options", "DENY")                                                                                                                                    // 防止点击劫持c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") // 防止跨站脚本攻击c.Header("X-XSS-Protection", "1; mode=block")                                                                                                                          // 启用 XSS 保护c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")                                                                                  // 强制使用 HTTPSc.Header("Referrer-Policy", "strict-origin")                                                                                                                           // 控制引用来源c.Header("X-Content-Type-Options", "nosniff")                                                                                                                          // 防止 MIME 类型嗅探c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()")                 // 控制特定功能的权限c.Next()                                                                                                                                                               // 继续处理请求})// 定义 GET 路由 /pingr.GET("/ping", func(c *gin.Context) {// 返回 JSON 响应,包含 "pong" 消息c.JSON(200, gin.H{"message": "pong", // 消息内容})})// 启动服务,监听 0.0.0.0:8080r.Run() // listen and serve on 0.0.0.0:8080
}

打开postman,输入http://localhost:8080/ping,此时直接点send,或者随意设置headers中的key和value,只要key不是host(不区分大小写),均能正常输出。但如果在headers中设置了key为host(不区分大小写),那么value就必须是代码中设置好的值,这里是localhost:8080,否则出错,如图:
在这里插入图片描述

四、使用BasicAuth中间件

package mainimport ("net/http""github.com/gin-gonic/gin"
)// 模拟一些私人数据,使用 map 结构存储用户的私人信息
var secrets = gin.H{"foo":    gin.H{"email": "foo@bar.com", "phone": "123433"},     // 用户 foo 的私人信息"austin": gin.H{"email": "austin@example.com", "phone": "666"}, // 用户 austin 的私人信息"lena":   gin.H{"email": "lena@guapa.com", "phone": "523443"},  // 用户 lena 的私人信息
}func main() {r := gin.Default() // 创建一个默认的 Gin 路由器// 路由组使用 gin.BasicAuth() 中间件,保护 /admin 路径// gin.Accounts 是 map[string]string 的一种快捷方式,设置用户和密码authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{"foo":    "bar",    // 用户 foo 的密码"austin": "1234",   // 用户 austin 的密码"lena":   "hello2", // 用户 lena 的密码"manu":   "4321",   // 用户 manu 的密码}))// /admin/secrets 端点处理,只有经过 Basic Auth 验证的用户可以访问// 当用户访问 "localhost:8080/admin/secrets" 时,将触发此处理函数authorized.GET("/secrets", func(c *gin.Context) {// 获取当前用户的信息,它是由 BasicAuth 中间件设置的user := c.MustGet(gin.AuthUserKey).(string)if secret, ok := secrets[user]; ok {// 如果找到了用户的私人信息,返回该信息c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})} else {// 如果未找到用户的私人信息,返回默认信息c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})}})// 监听并在 0.0.0.0:8080 上启动服务,等待请求r.Run(":8080")
}

效果
在这里插入图片描述

五、使用HTTP方法

package mainimport ("net/http""github.com/gin-gonic/gin"
)// 获取请求的处理函数
func getting(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "GET request successful"})
}// 处理 POST 请求的处理函数
func posting(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "POST request successful"})
}// 处理 PUT 请求的处理函数
func putting(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "PUT request successful"})
}// 处理 DELETE 请求的处理函数
func deleting(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "DELETE request successful"})
}// 处理 PATCH 请求的处理函数
func patching(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "PATCH request successful"})
}// 处理 HEAD 请求的处理函数
func head(c *gin.Context) {// HEAD 请求只返回状态和头部,不返回请求体c.Status(http.StatusOK) // 返回状态码 200
}// 处理 OPTIONS 请求的处理函数
func options(c *gin.Context) {// OPTIONS 请求返回允许的 HTTP 方法c.JSON(http.StatusOK, gin.H{"methods": "GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"})
}func main() {// 禁用控制台颜色// gin.DisableConsoleColor()// 使用默认中间件(logger 和 recovery 中间件)创建 gin 路由router := gin.Default()// 定义各个 HTTP 方法的路由及其处理函数router.GET("/someGet", getting)         // 处理 GET 请求router.POST("/somePost", posting)       // 处理 POST 请求router.PUT("/somePut", putting)         // 处理 PUT 请求router.DELETE("/someDelete", deleting)  // 处理 DELETE 请求router.PATCH("/somePatch", patching)    // 处理 PATCH 请求router.HEAD("/someHead", head)          // 处理 HEAD 请求router.OPTIONS("/someOptions", options) // 处理 OPTIONS 请求// 默认在 8080 端口启动服务,除非定义了一个 PORT 的环境变量。router.Run() // 启动服务并监听端口// router.Run(":3000") // 如果需要硬编码端口号,可以取消注释这一行
}

效果
使用 Postman 进行测试:
GET 请求:
选择 GET 方法,输入 URL http://localhost:8080/someGet,点击 Send。
POST 请求:
选择 POST 方法,输入 URL http://localhost:8080/somePost,点击 Send。
PUT 请求:
选择 PUT 方法,输入 URL http://localhost:8080/somePut,点击 Send。
DELETE 请求:
选择 DELETE 方法,输入 URL http://localhost:8080/someDelete,点击 Send。
PATCH 请求:
选择 PATCH 方法,输入 URL http://localhost:8080/somePatch,点击 Send。
HEAD 请求:
选择 HEAD 方法,输入 URL http://localhost:8080/someHead,点击 Send。
OPTIONS 请求:
选择 OPTIONS 方法,输入 URL http://localhost:8080/someOptions,点击 Send。
这里只展示一个:
在这里插入图片描述

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

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

相关文章

Redis Geo 数据类型解析:基于 ZSET 的高效地理位置管理0708

根据官网介绍: Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type which is treated like a bit vector. Since strings are binary safe blobs and their maximum length is 512 MB, they are suitable to s…

【回顾一下AQS知识,关于公平锁与非公平锁】

文章目录 一.什么是AQS二.公平锁和非公平锁实现三.公平锁和非公平锁的区别四.小结 一.什么是AQS AQS,全称 AbstractQueuedSynchronizer,是 Java 中用于构建锁和同步器的一个基础框架类,位于 java.util.concurrent.locks 包中。AQS 通过一个先…

Android 15 推出新安全功能以保护敏感数据

Android 15 带来了增强的安全功能,可保护您的敏感健康、财务和个人数据免遭盗窃和欺诈。 它还为大屏幕设备带来了生产力改进,并对相机、消息和密钥等应用进行了更新。 Android 防盗保护 Google 开发并严格测试了一套全面的功能,以在盗窃之…

Java基础(6)

深拷贝和浅拷贝区别了解吗?什么是引用拷贝?关于深拷贝和浅拷贝区别,我这里先给结论:浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部…

谷歌浏览器如何展示小于12px的字

在谷歌浏览器里面&#xff0c;字体最小只能设置为12px&#xff0c;但是我们有时候需要展示更小的文字。方法如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" co…

【计算机科学】什么是ASCII码?

引言 在计算机技术的世界里&#xff0c;字符编码是一个至关重要的概念&#xff0c;它决定了我们如何将文本字符存储、传输和处理。ASCII码&#xff08;American Standard Code for Information Interchange&#xff0c;美国信息交换标准代码&#xff09;是字符编码中的一项基础…

java关于如何实现读取各种类型的文件核心属性方法,比如获取标题和作者、主题等;附带远程的https的地址文件读取方法;

有两种方法&#xff1a; 通过提供的现成api进行调用读取pdf文件&#xff0c;或doc、xlsx、pptx文件&#xff1b;可能商业需要付费 https://www.e-iceblue.cn/pdf_java_document_operation/set-pdf-document-properties-in-java.html Spire.PDF for Java import com.spire.pdf…

【洛谷】AT_abc188_c [ABC188C] ABC Tournament 的题解

【洛谷】AT_abc188_c [ABC188C] ABC Tournament 的题解 洛谷传送门 AT传送门 Vjudge传送门 题解 谔谔&#xff0c;最近月考&#xff0c;没时间写题解。现在终于有时间了qaq 通过对样例的数据分析我们可以看到。本题的考点就是一个二叉搜索树&#xff0c;因此最简单的方法…

Day31 || 122.买卖股票的最佳时机 II、55. 跳跃游戏、 45.跳跃游戏II 、1005.K次取反后最大化的数组和

122.买卖股票的最佳时机 II 题目链接&#xff1a;力扣题目链接 思路&#xff1a;因为是求虽大利润完全可以假设知道第二天涨前一天买入即可&#xff0c;就是求两天只差大于0 的和。 55. 跳跃游戏 题目链接&#xff1a;力扣题目链接 思路&#xff1a;应该从后往前循环判断&…

搜维尔科技:使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据

使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据 搜维尔科技&#xff1a;使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据

【初识数据库】

目录 一、数据库简介 1.什么是数据库 2.数据库与数据结构有啥关系 3.为什么要使用数据库 二、数据库服务器、数据库和表的关系 三、客户端与服务器的通讯方式 1.C/S架构 2.B/S架构 3.命令提示符 4.MySQL架构 一、数据库简介 1.什么是数据库 组织和保存数据的应用程序…

数据结构与算法JavaScript描述练习------第12章排序算法

1. 使用本章讨论的所有算法对字符串数据而非数字数据进行排序&#xff0c;并比较不同算法的执行 时间。这两者的结果是否一致呢&#xff1f; function CArray(numElements) { this.dataStore []; this.pos 0; this.numElements numElements; this.insert insert; this.toS…

HTTP安全么?如何更好的保护您的网站

在互联网飞速发展的今天&#xff0c;网络安全问题日益严峻。HTTP作为最常见的网络通信协议&#xff0c;虽然在传输效率方面表现优异&#xff0c;但其安全性却常常令人担忧。许多企业和个人网站在使用HTTP进行数据传输时&#xff0c;可能忽视了其中潜在的风险。那么&#xff0c;…

搜维尔科技:SenseGlove Nova 2触觉反馈手套开箱测评

SenseGlove Nova 2触觉反馈手套开箱测评 搜维尔科技&#xff1a;SenseGlove Nova 2触觉反馈手套开箱测评

react函数组件和类组件

react函数组件和类组件 函数组件会捕获render内部的差异&#xff0c;性能主要取决于代码正在进行的操作&#xff0c;函数组件和类组件区别可以忽略不计&#xff0c;但是优化策略是有不同的。 类组件 class Welcome extends React.Component {render() {return <h1>{th…

大模型入门到精通!大模型应用开发极简入门(含PDF)

大模型的出现正悄然改变人们的生活与工作方式&#xff0c;比如ChatGPT-4、文心一言、通义千问等语言大模型。它们已帮助很多办公室“白领”们在解决日常工作问题&#xff0c;如制定计划、撰写实施方案&#xff0c;甚至制作美化PPT等&#xff08;笔者及身边的同事在工作中还经常…

OpenCV人脸检测与识别:构建智能识别系统

在当今科技日新月异的时代&#xff0c;人脸识别技术以其独特的便利性和安全性&#xff0c;在各个领域都展现出了巨大的应用潜力。从智能手机的面部解锁&#xff0c;到机场的自动安检&#xff0c;再到商场的顾客行为分析&#xff0c;人脸识别技术无处不在。本文将深入探讨如何使…

简单认识redis - 9 布隆过滤器

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种空间效率很高的随机数据结构&#xff0c;用于判断一个元素是否可能在一个集合中。 一、工作原理 1. 初始化&#xff1a; 布隆过滤器由一个位数组&#xff08;通常是一个很长的二进制数组&#xff09;和若干个哈希函数组…

【scene_manager_msgs】ROS2 自定义消息、服务的包

scene_manager_msgs 在ROS 1向ROS 2迁移的过程中&#xff0c;有些依赖项发生了变化&#xff0c;这是因为ROS 2的通信框架和工具链与ROS 1不同&#xff0c;尤其在消息、服务和动作生成方面有了一些新的方法和库。 动作库 如果你的ROS 1包依赖于actionlib或actionlib_msgs&…

拍立淘API返回值中的商品列表与详细信息解析

拍立淘&#xff08;Pailitao&#xff09;是阿里巴巴旗下的一种图像识别购物技术&#xff0c;允许用户通过拍摄商品照片来搜索相似的商品。尽管官方没有直接开放拍立淘的API给公众使用&#xff0c;但可以通过淘宝开放平台&#xff08;Taobao Open Platform&#xff09;的一些图像…