23 go语言(golang) - gin框架安装及使用(四)

ops/2024/12/22 16:54:33/

五、跨域资源共享

跨域资源共享(CORS,Cross-Origin Resource Sharing)是一种机制,它允许来自不同源的请求访问资源。默认情况下,浏览器出于安全原因会阻止跨域 HTTP 请求。Gin 框架本身没有内置的 CORS 支持,但可以通过中间件轻松实现。

  • 同源策略:浏览器的安全策略,只允许同源请求访问资源。同源指的是协议、主机和端口都相同。

  • CORS 头:服务器通过设置特定的 HTTP 响应头来告诉浏览器它允许哪些来源可以访问其资源。

5.1 不配置CORS

假设你有一个前端应用运行在 http://localhost:3000,而后端服务是用 Gin 开发的,运行在 http://localhost:8080。前端需要通过 AJAX 请求调用后端的 API。

如果没有配置 CORS,当浏览器尝试从 http://localhost:3000 发起请求到 http://localhost:8080 时,会因为跨域限制而被阻止。

5.1.1 后端代码

启动服务

func Test1(t *testing.T) {r := gin.Default()r.GET("/test", func(c *gin.Context) {c.JSON(200, gin.H{"message": "成功进入test路由!",})})r.Run()
}

5.1.2 前端代码(发起跨域请求)

创建一个名为 index.html 的文件,并将以下内容粘贴进去:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Fetch API Example</title>
</head>
<body><h1>Fetch API Example</h1><script>// 使用 Fetch API 发起请求到后端接口fetch('http://localhost:8080/test').then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));
</script></body>
</html>

5.1.3 测试

方式一:用浏览器打开index.html

方式二(我用的这种方式):为了更方便地查看和调试前端代码,可以使用 Python 提供的简易 HTTP 服务器。在终端中导航到项目目录,然后运行

python -m http.server 3000

这会在 http://localhost:3000 启动一个简单的 HTTP 静态文件服务器。

然后再在浏览器访问 http://localhost:3000/index.html

5.1.4 测试结果

打开浏览器开发者工具(通常按 F12 或右键点击页面选择“检查”),切换到“console”标签页

在这里插入图片描述

这是因为浏览器默认出于安全考虑,不允许从不同源(不同协议、域名或端口)的页面访问资源。如果服务器未正确设置允许跨域访问的响应头,就会触发这个错误。

Access to fetch at 'http://localhost:8080/test' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

5.2 配置CORS

5.2.1 安装 CORS 中间件库

github.com/gin-contrib/cors 是一个常用的 Gin 中间件库。

安装命令:

go get github.com/gin-contrib/cors

5.2.2 配置和使用中间件

最简单的,使用默认的配置

	// 使用默认选项r.Use(cors.Default())

或者自定义配置

func Test3(t *testing.T) {r := gin.Default()// 或者自定义配置r.Use(cors.New(cors.Config{AllowOrigins:     []string{"http://localhost:3000"},AllowMethods:     []string{"GET", "POST", "PUT"},AllowHeaders:     []string{"Origin", "Content-Type"},ExposeHeaders:    []string{"Content-Length"},AllowCredentials: true,MaxAge:           12 * time.Hour,}))r.GET("/test", func(c *gin.Context) {c.JSON(200, gin.H{"message": "成功进入test路由!",})})r.Run()
}

配置选项解释

  • AllowOrigins: 指定哪些域名可以进行跨域请求。如果要允许所有域名,可以使用 "*"

  • AllowMethods: 指定哪些 HTTP 方法被允许用于跨域请求,如 GET、POST 等。

  • AllowHeaders: 指定客户端在预检请求(preflight request)时能发送哪些自定义头部字段。

  • ExposeHeaders: 列出哪些响应头部信息可以暴露给外部 JavaScript 程序。

  • AllowCredentials: 是否允许发送 Cookie 信息。如果设置为 true,则不能将 AllowOrigins 设置为 "*",而必须指定具体的 URL。

  • MaxAge: 指示预检请求结果能够被缓存多长时间,以减少客户端与服务器之间不必要的通信。

5.2.3 再次测试结果

在这里插入图片描述

六、授权与认证

在Gin框架中,实现授权和认证通常涉及到用户身份验证(Authentication)和权限控制(Authorization)。这两者是确保应用程序安全性的重要组成部分。

6.1 认证(Authentication)

认证是指验证用户身份的过程。常见的方法包括使用用户名和密码、OAuth、JWT等。在Gin中,通常通过中间件来处理认证逻辑。

这里我们使用JWT(JSON Web Token),它是一种用于在各方之间作为JSON对象安全地传输信息的紧凑、URL安全的方式。广泛应用于Web应用程序中,用于实现用户认证和授权。

  1. 用户登录:接收用户名和密码,验证后生成并返回一个JWT。
  2. 请求保护资源:客户端在请求头或Cookie中携带JWT。
  3. 解析与验证JWT:服务器端通过解析该令牌以确认其有效性,并提取其中的声明信息。

6.1.1 安装JWT

官方文档

go get -u github.com/golang-jwt/jwt/v5

6.1.2 使用

6.1.2.1 生成新的token

1、首先定义一个登录接口

type LoginInfo struct {Username string `json:"username" binding:"required"`Password string `json:"password" binding:"required"`
}func Test4(t *testing.T) {r := gin.Default()// 模拟用户登录操作r.POST("login", func(c *gin.Context) {var loginInfo LoginInfoif err := c.ShouldBindJSON(&loginInfo); loginInfo.Password != "123123" || err != nil {// 简单模拟校验密码是否正确c.JSON(http.StatusBadRequest, gin.H{"msg": "用户名或密码错误",})return}c.JSON(http.StatusOK, gin.H{"msg": "登录成功",})})r.Run()
}

2、然后实现登录验证成功后生成并返回一个JWT token的方法

// 定义一个密钥
var jwtKey = []byte("这是个密钥 private key")// token
type Claims struct {Username             stringjwt.RegisteredClaims // 官方提供的实现了Claims接口的类
}// 登录成功后生成一个有效时间为5分钟的token
func LoginSuccess(username string) string {expirationTime := time.Now().Add(time.Minute * 5)claims := &Claims{Username: username,RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(expirationTime),},}// 注册一个新的token,需要传入注册方法和实现Claims接口的类token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)tokenString, _ := token.SignedString(jwtKey)fmt.Println(tokenString)return tokenString
}

3、应用在login接口中

		...// 登录成功后,注册一个token并通过cookie返回给客户tokenStr := LoginSuccess(loginInfo.Username)c.SetCookie("token", tokenStr, 300, "/", "", false, true)c.JSON(http.StatusOK, gin.H{"msg": "登录成功",})
}

4、调用login接口成功后,应该在cookie中能看到token

在这里插入图片描述

6.1.2.2 验证cookie中的token

定义一个gin的中间件,用于校验token,如果校验成功则进行c.Next(),否则不通过

// 定义校验token的中间件
func CheckToken() gin.HandlerFunc {return func(c *gin.Context) {// 获取cookie中的tokentokenStr, err := c.Cookie("token")if err != nil {c.Abort()c.JSON(http.StatusUnauthorized, gin.H{"msg": "请重新登录",})}// 校验tokenclaims := &Claims{}tkn, err := jwt.ParseWithClaims(tokenStr, claims,func(token *jwt.Token) (interface{}, error) { return jwtKey, nil })if !tkn.Valid || err != nil {c.JSON(http.StatusUnauthorized, gin.H{"msg": "请重新登录",})return}// 可以将用户信息放进context中,方便后续使用c.Set("username", claims.Username)c.Next()}
}

定义一个新的接口,并应用这个中间件

r.Use(CheckToken())r.GET("/homepage", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "欢迎你," + c.GetString("username"),})})

将之前的cookie中的token复制到新的窗口中调用homepage接口

在这里插入图片描述

6.2 授权(Authorization)

授权是在确认用户身份之后,决定其是否有权访问特定资源或执行某些操作的过程。常见的方法包括基于角色的访问控制(RBAC)和基于属性的访问控制(ABAC)。

6.2.1 基于角色的访问控制

RBAC根据用户所属角色来授予权限。例如,一个管理员可能有权访问所有资源,而普通用户只能查看自己的数据。

func CheckRole() gin.HandlerFunc {return func(c *gin.Context) {username := c.GetString("username")if role := getRole(username); role != "admin" {c.Abort()c.JSON(http.StatusForbidden, gin.H{"msg": "抱歉,没有权限访问",})return}// 如果有权限,则继续处理请求c.Next()}
}func getRole(username string) string {// 模拟从数据库查询该用户的角色if username == "admin" {return "admin"} else {return "user"}
}

然后定义一个新的路由组,应用这个中间件

  group := r.Group("menu")group.Use(CheckRole())group.GET("list", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "成功访问菜单",})})

http://www.ppmy.cn/ops/144073.html

相关文章

SQL server学习07-查询数据表中的数据(下)

目录 一&#xff0c;自连接查询 二&#xff0c;多表查询 三&#xff0c;关系代数运算 1&#xff0c;笛卡尔乘积运算 1&#xff09;交叉连接 2&#xff0c;连接运算 2&#xff09;内连接 四&#xff0c;外连接 1&#xff0c;左外连接 2&#xff0c;右外连接 3&…

12. 最大括号深度

题目描述 现有一字符串仅由"("&#xff0c;")", "{","}", "[", "]"六种括号组成。若字符串满足以下条件之一&#xff0c; 则为无效字符串:任一类型的左右括号数量不相等 存在未按正确顺序(先左后右)闭合的括号输出…

FFmpeg 安装教程(Windows 系统)

1. 前言 FFmpeg 是一个用于处理视频、音频等多媒体文件的开源工具包。它支持几乎所有的多媒体格式转换、剪辑和编辑&#xff0c;是开发者和多媒体工作者必备的工具。本文详细讲解如何在 Windows 系统上安装 FFmpeg 并进行基本配置。 2. 下载 FFmpeg 安装包 打开 Dpwnload FFmp…

Android Room 数据库使用详解

一、Room介绍 Android Room 是 Google 提供的一个 Android 数据持久化库&#xff0c;是 Android Jetpack 组成部分之一。它提供了一个抽象层&#xff0c;使得 SQLite 数据库的使用更为便捷。通过 Room&#xff0c;开发者可以轻松地操作数据库&#xff0c;不需要直接编写繁琐的…

二、使用langchain搭建RAG:金融问答机器人--数据清洗和切片

选择金融领域的专业文档作为源文件 这里选择 《博金大模型挑战赛-金融千问14b数据集》&#xff0c;这个数据集包含若干公司的年报&#xff0c;我们将利用这个年报搭建金融问答机器人。 具体下载地址 这里 git clone https://www.modelscope.cn/datasets/BJQW14B/bs_challenge_…

智慧商城:购物车模块基本静态结构 + 构建vuex cart模块,获取数据存储(异步actions)

基本静态结构 静态结构直接 cv笔记中的内容 &#xff0c;粘贴到 layout架子上的 cart组件中 给详情页底部的 首页 和 购物车 添加点击跳转事件 cart.vue中应用到的 van-Checkbox组件&#xff0c;进行该组件的引入注册 将数字框替换为之前封装好(两个-按钮中间的1那个输入框)的组…

如果模块请求http改为了https,测试方案应该如何制定,修改

作者&#xff1a;逍遥Sean 简介&#xff1a;一个主修Java的Web网站\游戏服务器后端开发者 主页&#xff1a;https://blog.csdn.net/Ureliable 觉得博主文章不错的话&#xff0c;可以三连支持一下~ 如有疑问和建议&#xff0c;请私信或评论留言&#xff01; 前言 将模块的请求协…

电脑频繁弹出“缺少d3dcompiler_47.dll”提示?“缺少d3dcompiler_47.dll”要怎么解决?

电脑频繁弹出“缺少d3dcompiler_47.dll”提示&#xff1f;一文带你了解原因与解决方案 在日常使用电脑的过程中&#xff0c;不少用户可能会遇到系统频繁弹出“缺少d3dcompiler_47.dll”的提示。这个看似陌生的文件名&#xff0c;实则对电脑游戏的运行至关重要。d3dcompiler_47…