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 main

import (
	"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 路由 /foo
	r.POST("/foo", func(c *gin.Context) {
		// 返回 JSON 响应,内容为 "foo" 和 HTTP 状态码 200
		c.JSON(http.StatusOK, "foo")
	})

	// 定义 GET 路由 /bar
	r.GET("/bar", func(c *gin.Context) {
		// 返回 JSON 响应,内容为 "bar" 和 HTTP 状态码 200
		c.JSON(http.StatusOK, "bar")
	})

	// 定义 GET 路由 /status
	r.GET("/status", func(c *gin.Context) {
		// 返回 JSON 响应,内容为 "ok" 和 HTTP 状态码 200
		c.JSON(http.StatusOK, "ok")
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run() // 启动 Gin 路由引擎
}

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

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

二、如何记录日志

package main

import (
	"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 路由 /ping
	router.GET("/ping", func(c *gin.Context) {
		// 返回字符串 "pong" 和 HTTP 状态码 200
		c.String(200, "pong")
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	router.Run(":8080") // 启动 Gin 路由引擎
}

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

三、安全页眉

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

package main

import (
	"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")                                                                                  // 强制使用 HTTPS
		c.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 路由 /ping
	r.GET("/ping", func(c *gin.Context) {
		// 返回 JSON 响应,包含 "pong" 消息
		c.JSON(200, gin.H{
			"message": "pong", // 消息内容
		})
	})

	// 启动服务,监听 0.0.0.0:8080
	r.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 main

import (
	"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 main

import (
	"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。
这里只展示一个:
在这里插入图片描述

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

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

相关文章

Docker-Harbor概述及构建

文章目录 一、Docker Harbor概述1.Harbor的特性2.Harbor的构成 二、搭建本地私有仓库三、部署 Docker-Harbor 服务四、在其他客户端上传镜像五、维护管理Harbor 一、Docker Harbor概述 Harbor 是 VMware 公司开源的企业级 Docker Registry 项目,其目标是帮助用户迅…

Java项目-基于springboot框架的社区疫情防控平台系统项目实战(附源码+文档)

作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…

新手必须掌握的Linux命令

1.1 常用系统工作命令 echo [linuxprobelocalhost /]$ echo $SHELL /bin/bash 使用$变量的方式提取SHELL的值,并输出到到屏幕上 date [linuxprobelocalhost /]$ date -s "20170901 8:30:00" 将系统时间设置为 reboot ----系统重启命令poweroff --…

数据结构与算法:数据结构的前沿研究(最终章)

目录 18.1 可持久化数据结构 18.2 随机化数据结构 18.3 内存与存储优化的数据结构 18.4 新兴数据结构与未来趋势 18.5 研究前沿与挑战 总结 数据结构与算法:数据结构的前沿研究(最终章) 随着计算机科学和技术的不断发展,数…

【设计模式系列】模板方法模式

一、什么是模板方法模式 模板方法模式(Template Method Pattern)是一种行为型设计模式,它在父类中定义一个算法的框架,允许子类在不改变算法结构的情况下重写算法的某些特定步骤。这种模式非常适合于那些存在共同行为的类&#x…

【win11】终端/命令提示符/powershell美化

文章目录 1.设置字体1.1. 打开win11的终端/命令提示符/powershell其中之一1.2. 打开终端设置,修改所有终端默认字体为新宋体 2. 修改powershell背景色为蓝色 win11的默认终端/命令提示符/powershell主题风格让人感觉与win10撕裂太大,尤其是字体、背景色&…

java宠物商城源码

题目:java宠物商城源码 主要内容:毕业设计(Javaweb项目|小程序|Mysql|大数据|SSM|SpringBoot|Vue|Jsp|MYSQL等)、学习资料、JAVA源码、技术咨询 文末联系获取 感兴趣可以先收藏起来,以防走丢,有任何选题、文档编写、代码问题也…

(五)若使用LQR控制小车倒立摆,该如何对小车和摆杆的动力学方程线性化?哪些变量是可以进行简化的,线性化后的状态空间方程应该怎么列写

写在前面: 关于lqr控制的讲解,可以观看如下三个视频: 2. LQR数学公式理解_哔哩哔哩_bilibili 如何感性地理解LQR控制?_哔哩哔哩_bilibili LQR简介与使用_哔哩哔哩_bilibili 正文: 在之前系列的文章中我们已经得出…

搭建localhost本地 ChatGPT 模型与总结

搭建本地 ChatGPT 模型的步骤可以分为几个主要部分。以下是一个概述,包括所需工具、步骤和总结。 ### 所需工具与环境 1. **硬件要求**: - 一台具有良好计算能力的电脑或服务器,最好配备 GPU。 2. **软件要求**: - Pytho…

Linux LCD 驱动实验

LCD 是很常用的一个外设,在裸机篇中我们讲解了如何编写 LCD 裸机驱动,在 Linux 下LCD 的使用更加广泛,再搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。本章我们就来学习一下如何在 Linux 下驱动 LCD 屏幕。 Framebuffer 设备 先来…

视频的编解码格式

文章目录 视频的编解码格式概念术语视频处理流程视频封装格式视频编码格式视频编解码器,视频容器和视频文件格式之间的区别补充视频码率 参考资料 视频的编解码格式 概念术语 两大组织主导视频压缩的组织及其联合(joint)组织 ITU-T(VCEG) ITU-T的中文名称是国际电信…

论文翻译 | A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT (下)

I.事实核查表模式 1)意图和上下文:此模式的目的是确保LLM输出一个事实列表,这些事实存在于输出中,并构成输出中语句的重要组成部分。此事实列表有助于告知用户输出所基于的事实(或假设)。然后,用户可以对这…

python将照片集导出成视频

shigen坚持更新文章的博客写手,记录成长,分享认知,留住感动。个人IP:shigen 背景 一个安静的下午,看着电脑里乱七八糟的照片,有大有小,宽高不一,突然想找个方式把他们统一起来&…

求最大公约数(c语言)

先看题👇 我这里介绍的方法:辗转相除法: 最大公约数: 最大公约数是指同时能整除俩个或更多整数的最大正整数。 欧几里得算法就是求最大公约数的算法 求最大公约数涉及到一个数学原理的转换: 俩个数的最大公约数等于其中一个数和…

使用scss生成旋转圆圈

图片 html代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>…

Windows电脑桌面如何弄个好用的提醒备忘录?

在这个充满挑战的时代&#xff0c;每个人都渴望成为更好的自己。然而&#xff0c;随着生活节奏的加快&#xff0c;我们时常发现自己陷入了各种琐事之中&#xff0c;难以脱身。为了不让重要的事情被遗漏&#xff0c;一款好的提醒备忘录工具就显得尤为关键。那么&#xff0c;Wind…

白嫖正版xshell和XFTP

在哪里可以下载正版免费的xshell和XFTP&#xff0c;并且还能够获得官网免费持久更新 白嫖步骤 首先直接在浏览器搜索xshell官网 点进官网之后直接点击下载 接着点击免费授权页面 进入之后就可以免费下载了 下载安装完成后填写用户名和邮箱并提交&#xff0c;这里就以xshell为…

第6篇:无线与移动网络

目录 引言 6.1 无线网络的基础概念 6.2 无线局域网&#xff08;WLAN&#xff09;与IEEE 802.11 6.3 蓝牙与无线个域网&#xff08;WPAN&#xff09; 6.4 无线城域网&#xff08;WMAN&#xff09;与WiMax 6.5 ZigBee与智能家居 6.6 移动蜂窝网络&#xff08;3G/4G/5G&…

【str_replace替换导致的绕过】

双写绕过 随便输入一个 usernameadmin&passwords 没有回显测试注入点 usernameadmin or 11%23&passwords 回显hello admin测试列数 usernameadmin order by 3%23&passwords测试回显位 usernameadmi union select 1,2,3%23&passwords 没有显示数据&#xff0c;推…

如何保证数据库和缓存双写一致性?

1. 如何保证数据库和缓存双写一致性&#xff1f; 在高并发情况下&#xff0c;如果有大量的请求直接访问到数据库&#xff0c;由于数据库是将数据存储到磁盘当中的&#xff0c;每次访问时需要将数据以页的形式读取到内存当中&#xff0c;并且建立数据库连接、查询数据库中的数据…