golang gin——中间件编程以及jwt认证和跨域配置中间件案例
中间件编程+jwt认证
在不改变原有方法的基础上,添加自己的业务逻辑。相当于grpc中的拦截器一样,在不改变grpc请求的同时,插入自己的业务。
简单例子
func Sum(a, b int) int {return a + b
}func LoggerMiddleware(in func(a, b int) int) func(a, b int) int {return func(a, b int) int {log.Println("logger middleware")return in(a, b)}
}func main() {f := SumLoggerMiddleware(f)(1, 2)
}
D:\goProject\gobasic\goGin>go run main.go
2023/10/07 12:21:58 logger middleware
gin 中间件编程
Gin 内置支持了中间件的逻辑
使用use。或者路由分组的时候也可以使用
r := gin.New()
r.User(gin.Logger(), gin.Recovery())
跨域和jwt认证
什么是跨域
由于浏览器的同源策略限制,进而产生跨域拦截问题。同源策略是浏览器最核心也最基本的安全功能;所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略分为两种:
- DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
- XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
同源策略在解决浏览器访问安全的同时,也带来了跨域问题,当一个请求url的协议
、域名
、端口
三者之间任意一个与当前页面url不同即为跨域。
使用cors解决跨域问题
CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。CORS 需要浏览器和服务器同时支持。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
简单请求
- 请求方法为 HEAD、GET、POST中的一种。
- HTTP头信息不超过一下几种:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
对于简单请求,浏览器回自动在请求的头部添加一个 Origin
字段来说明本次请求来自哪个源(协议 + 域名 + 端口),服务端则通过这个值判断是否接收本次请求。如果 Origin
在许可范围内,则服务器返回的响应会多出几个头信息:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Content-Length
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
实际上后续我们就是通过在服务端配置这些参数来处理跨域请求的。
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是 PUT 或 DELETE ,或者 Content-Type 字段的类型是 application/json。 或者修改了请求头
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),预检请求其实就是我们常说的 OPTIONS 请求,表示这个请求是用来询问的。头信息里面,关键字段 Origin ,表示请求来自哪个源,除 Origin 字段,"预检"请求的头信息包括两个特殊字段:
//该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法
Access-Control-Request-Method
//该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段.
Access-Control-Request-Headers
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest
请求,否则就报错。
golang配置cors解决跨域问题
上述介绍了两种跨域请求,其中出现了几种特殊的 Header 字段,CORS 就是通过配置这些字段来解决跨域问题的:
-
Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求 -
Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。 -
Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers
字段,则Access-Control-Allow-Headers
字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。 -
Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的response只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。 -
Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie
。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie,删除该字段即可。 -
Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒,在此期间,不用发出另一条预检请求
以gin框架为例子,配置跨域中间件
package middlewareimport ("github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)func Cors() gin.HandlerFunc {return cors.New(cors.Config{// 允许所有域名访问AllowAllOrigins: true,// 允许请求头中的字段,AllowHeaders: []string{"Origin", "Content-Length", "Content-Type",},// 允许请求的方法AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS",},})
}
然后在路由分组或者引擎初始化的时候可以添加。 一般在路由分组时候添加
JWT认证中间件
Json Web Token(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准RFC7519。JWT一般可以用作独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,特别适用于分布式站点的登录场景。
JWT的构成
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
如上面的例子所示,JWT就是一个字符串,由三部分构成:
- Header(头部)
- Payload(数据)
- Signature(签名)
header
JWT的头部承载两个信息:
- 声明类型,这里是JWT
- 声明加密的算法
{'typ': 'JWT','alg': 'HS256'
}
然后将头部进行Base64编码(该编码是可以对称解码的),构成了第一部分。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
payload
载荷就是存放有效信息的地方。定义细节如下:
iss:令牌颁发者。表示该令牌由谁创建,该声明是一个字符串
sub: Subject Identifier,iss提供的终端用户的标识,在iss范围内唯一,最长为255个ASCII个字符,区分大小写
aud:Audience(s),令牌的受众,分大小写的字符串数组
exp:Expiration time,令牌的过期时间戳。超过此时间的token会作废, 该声明是一个整数,是1970年1月1日以来的秒数
iat: 令牌的颁发时间,该声明是一个整数,是1970年1月1日以来的秒数
jti: 令牌的唯一标识,该声明的值在令牌颁发者创建的每一个令牌中都是唯一的,为了防止冲突,它通常是一个密码学随机值。这个值相当于向结构化令牌中加入了一个攻击者无法获得的随机熵组件,有利于防止令牌猜测攻击和重放攻击。
也可以新增用户系统需要使用的自定义字段
然后将其进行Base64编码,得到Jwt的第二部分:
JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE
Signature
这个部分需要Base64编码后的Header和Base64编码后的Payload使用 .
连接组成的字符串,然后通过Header中声明的加密方式进行加密($secret
表示用户的私钥),然后就构成了jwt的第三部分。
// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');
将这三部分用 .
连接成一个完整的字符串,就构成了 jwt
JWT几个特点
- JWT 默认是不加密,不能将秘密数据写入 JWT。
- JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
- JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
- 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用HTTPS 协议传输。
跨域配置 + jwt认证案例
jwt加签验签
package jwt_pluginimport "github.com/golang-jwt/jwt/v4"
// 实际项目放配置文件
var key = "zxvfffsa123"// payload 添加自定义字段
type Data struct {Name string `json:"name"`Age int `json:"age"`Gender int `json:"gender"`jwt.RegisteredClaims
}
//签名
func Sign(data jwt.Claims) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, data)sign, err := token.SignedString([]byte(key))if err != nil {return "", err}return sign, err
}// 验签func Verify(sign string, data jwt.Claims) error {_, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {return []byte(key), nil})return err
}
登录认证
api + 路由
package routersimport ("github.com/gin-gonic/gin""github.com/golang-jwt/jwt/v4""goGin/jwt_plugin""net/http""time"
)func initLogin(group *gin.RouterGroup) {v1 := group.Group("/v1"){// 正常应该post登录v1.GET("/login", login.Login)}
}func Login(c *gin.Context) {data := jwt_plugin.Data{Name: "golang",Age: 17,Gender: 1,RegisteredClaims: jwt.RegisteredClaims{// 一小时过期ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),//签发时间IssuedAt: jwt.NewNumericDate(time.Now()),// 生效时间NotBefore: jwt.NewNumericDate(time.Now()),},}sign, err := jwt_plugin.Sign(data)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error(),})}c.JSON(http.StatusOK, gin.H{"access_token": sign,})
}
路由初始化
package routersimport ("github.com/gin-gonic/gin""goGin/middleware""goGin/user"
)func InitRouters(r *gin.Engine) {//使用路由分组// 添加跨域api := r.Group("/api")api.Use(middleware.Cors(), middleware.Auth())initUser(api)// 除了登录以外的 不需要认证notAuthApi := r.Group("/api")notAuthApi.Use(middleware.Cors())initLogin(notAuthApi)
}func initUser(group *gin.RouterGroup) {// 路由分组v1 := group.Group("/v1"){// /api/v1/course// 路径携带参数v1.GET("/user/:id", user.Get)v1.POST("/user/:id", user.Add)}// v2版本v2 := group.Group("v2"){v2.GET("/user/:id", user.GetV2)v2.POST("/user/:id", user.AddV2)}
}
其他API
user.go
package userimport ("github.com/gin-gonic/gin""net/http"
)type user struct {Name string `json:"name" binding:"required, alphaunicode"`Age int `json:"age" binding:"omitempty, number"` // 允许为空Phone string `json:"phone" binding:"omitempty, e164"`Email string `json:"email" binding:"omitempty, email"`
}func Add(c *gin.Context) {req := &user{}err := c.ShouldBindJSON(req)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error(),})}// 都是gin.context作为入参c.JSON(http.StatusOK, gin.H{"method": c.Request.Method,"path": c.Request.URL.Path,"req": req,})
}func Get(c *gin.Context) {id := c.Param("id")// 都是gin.context作为入参c.JSON(http.StatusOK, gin.H{"method": c.Request.Method,"path": c.Request.URL.Path,"id": id,})
}func AddV2(c *gin.Context) {// 都是gin.context作为入参c.JSON(http.StatusOK, gin.H{"method": c.Request.Method,"path": c.Request.URL.Path,})
}func GetV2(c *gin.Context) {authInfo, _:= c.Get("auth_info")// 都是gin.context作为入参c.JSON(http.StatusOK, gin.H{"method": c.Request.Method,"path": c.Request.URL.Path,"auth_info": authInfo,})
}
测试
认证,验签
不带token
相关文章:

golang gin——中间件编程以及jwt认证和跨域配置中间件案例
中间件编程jwt认证 在不改变原有方法的基础上,添加自己的业务逻辑。相当于grpc中的拦截器一样,在不改变grpc请求的同时,插入自己的业务。 简单例子 func Sum(a, b int) int {return a b }func LoggerMiddleware(in func(a, b int) int) f…...

如何快速制作令人惊叹的长图海报
在当今的数字时代,制作一张吸引人的长图海报已成为许多人的需求。无论是为了宣传活动,还是展示产品,一张设计精美的长图海报都能引起人们的注意。下面,我们将介绍一种简单的方法,使用在线海报制作工具来创建长图海报。…...

D (1092) : DS循环链表—约瑟夫环(Ver. I - A)
Description N个人坐成一个圆环(编号为1 - N),从第S个人开始报数,数到K的人出列,后面的人重新从1开始报数。依次输出出列人的编号。 例如:N 3,K 2,S 1。 2号先出列,然…...

Python爬虫(二十二)_selenium案例:模拟登陆豆瓣
本篇博客主要用于介绍如何使用seleniumphantomJS模拟登陆豆瓣,没有考虑验证码的问题,更多内容,请参考:Python学习指南 #-*- coding:utf-8 -*-from selenium import webdriver from selenium.webdriver.common.keys import Keysimp…...

1. Flink程序打Jar包
文章目录 步骤注意事项 步骤 用 maven 打 jar 包,需要在 pom.xml 文件中添加打包插件依赖 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><ver…...

水波纹文字效果动画
效果展示 CSS 知识点 text-shadow 属性绘制立体文字clip-path 属性来绘制水波纹 工具网站 CSS clip-path maker 效果编辑器 页面整体结构实现 使用多个 H2 标签来实现水波纹的效果实现,然后使用clip-path结合动画属性一起来进行波浪的起伏动画实现。 <div …...

【1.1】神经网络:关于神经网络的介绍
✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏: 神经网络(随缘更新) ✨特色…...

java项目中git的.ignore文件设置
在Git中,ignore是用来指定Git应该忽略的故意不被追踪的文件。它并不影响已经被Git追踪的文件。我们可以通过.ignore文件在Git中指定要忽略的文件。 当我们执行git add命令时,Git会检查.gitignore文件,并自动忽略这些文件和目录。这样可以避免…...

11.3 读图举例
一、低频功率放大电路 图11.3.1所示为实用低频功率放大电路,最大输出功率为 7 W 7\,\textrm W 7W。其中 A \textrm A A 的型号为 LF356N, T 1 T_1 T1 和 T 3 T_3 T3 的型号为 2SC1815, T 4 T_4 T4 的型号为 2SD525, T 2…...

黑马JVM总结(二十八)
(1)语法糖-foreach (2)语法糖-switch-string (3)语法糖-switch-enum (4)语法糖-枚举类 枚举类 (5)语法糖-twr1...

2023年DDoS攻击发展趋势的分析和推断
DDoS是一种非常“古老”的网络攻击技术,随着近年来地缘政治冲突对数字经济格局的影响,DDoS攻击数量不断创下新高,其攻击的规模也越来越大。日前,安全网站Latest Hacking News根据DDoS攻击防护服务商Link11的统计数据,对…...

RT-Thread 内存管理(学习二)
内存堆管理应用示例 这是一个内存堆的应用示例,这个程序会创建一个动态的线程,这个线程会动态申请内存并释放,每次申请更大的内存,当申请不到的时候就结束。 #include <rtthread.h>#define THREAD_PRIORITY 25 #defi…...

怎么修改jupyter lab 的工作路径而不是直接再桌面路径打开
要修改Jupyter Lab的工作路径,你可以按照以下步骤操作: 打开终端或命令提示符窗口。 输入 jupyter lab --generate-config 命令来生成Jupyter Lab的配置文件。 找到生成的配置文件,通常会位于 ~/.jupyter/jupyter_notebook_config.py。 使…...

高精度NTP时钟服务器(时间同步服务器)技术方案探讨
高精度NTP时钟服务器(时间同步服务器)技术方案探讨 高精度NTP时钟服务器(时间同步服务器)技术方案探讨 四分天下目前,全球的 GPS卫星同步系统处于“四分天下”状态,以美俄两国的系统处于领导地位ÿ…...

LFU 缓存 -- LinkedHashSet
相关题目: 460. LFU 缓存 相关文章 LRU 缓存 – 哈希链表 # 460. LFU 缓存 # Python中和 LinkedHashSet 相似的数据结构 OrderedDict from collections import OrderedDict class LFUCache:# key 到 val 的映射,我们后文称为 KV 表keyToVal {}# key 到…...

用IDEA操作数据库--MySQL
IDEA集成了DataGrip的操作数据库的功能 就可以省略我们下载SQLyog/Navicat/DataGrip这些图形化操作工具了 以下是IDEA的使用 输入数据库的用户和密码...

扫雷游戏的递归解法
目录 一,题目 二,题目接口 三,解题思路 四,解题代码 一,题目 让我们一起来玩扫雷游戏! 给你一个大小为 m x n 二维字符矩阵 board ,表示扫雷游戏的盘面,其中: M 代表一…...

java练习 day5
一、Nim 游戏 1、题目链接 点击跳转到题目位置 2、代码 class Solution {public boolean canWinNim(int n) {if(n % 4 0){return false;}return true;} }3、知识点 (1) 通过模拟来寻找 规律。 二、区域和检索 - 数组不可变 1、题目链接 点击跳转到题目位置 2、代码 …...

腾讯云轻量和CVM有啥区别?怎么选择服务器配置?
腾讯云轻量服务器和云服务器有什么区别?为什么轻量应用服务器价格便宜?是因为轻量服务器CPU内存性能比云服务器CVM性能差吗?轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境,云服务器CV…...

服务器or虚拟机安装SSH和虚拟机or服务器设置远程服务权限
第一步 服务器/虚拟机安装SSH工具,这是外部SSH终端连接服务器/虚拟机的第一步! sudo apt update && sudo apt upgrade#更新apt sudo apt install openssh-server#安装SSH工具 service ssh status#查看SSh运行状态 sudo systemctl enable --now ssh#运行SSH工具第二步…...

Sentinel入门
文章目录 初始Sentinel雪崩问题服务保护技术对比认识Sentinel微服务整合Sentinel 限流规则快速入门流控模式关联模式链路模式 流控效果warm up排队等待 热点参数限流全局参数限流热点参数限流 隔离和降级FeignClient整合Sentinel线程隔离熔断降级慢调用异常比例、异常数 授权规…...

Mac解压缩软件BetterZip免费版注册码下载
软件介绍 BetterZip免费版是一款适用于Mac系统的解压缩软件,软件具备了专业、实用、简单等特点,它可以让用户更快捷的向压缩文件中添加和删除文件,同时兼容性也十分优秀,支持ZIP , SIT , TAR、BZIP2 &…...

在win10里顺利安装了apache2.4.41和php7.4.29以及mysql8.0.33
一、安装apache和php 最近在学习网站搭建。其中有一项内容是在windows操作系统里搭建apachephp环境。几天前根据一本书的上的说明尝试了一下,在win10操作系统里安装这两个软件:apache2.4.41和php7.4.29,安装以后apche能正常启动,…...

云服务仿真:完全模拟 AWS 服务的本地体验 | 开源日报 No.45
localstack/localstack Stars: 48.7k License: NOASSERTION LocalStack 是一个云服务仿真器,可以在您的笔记本电脑或 CI 环境中以单个容器运行。它提供了一个易于使用的测试/模拟框架,用于开发云应用程序。主要功能包括: 在本地机器上完全…...

css实现不规则图片文字环绕效果
依旧,先上效果图,可以看见,文字环绕这个椭圆形的图片, 依旧是遵循开源精神,代码就直接放下面了 (点个赞或者给个评论啥的吧,我就发现我的文章全是光看不点赞,不评论的的) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8&quo…...

Day-05 CentOS7.5 安装 Docker
参考 : Install Docker Engine on CentOS | Docker DocsLearn how to install Docker Engine on CentOS. These instructions cover the different installation methods, how to uninstall, and next steps.https://docs.docker.com/engine/install/centos/ Doc…...

激光雷达:自动驾驶的眼睛
激光雷达:自动驾驶的眼睛 文章目录 引言激光雷达的原理自动驾驶中的应用激光雷达的优势激光雷达的挑战结论结论 2023星火培训【专项营】Apollo开发者社区布道师倾力打造,包含PnC、新感知等的全新专项课程上线了。理论与实践相结合,全新的PnC培…...

Scratch3.0下载
通俗易懂,直接上链接 链接:https://pan.baidu.com/s/1n-QFEQWT8im8BHQu1wIjtg?pwd1016 提取码:1016...

多功能频率计周期/脉宽/占空比/频率测量verilog,视频/代码
名称:多功能频率计周期、脉宽、占空比、频率测量verilog 软件:Quartus 语言:Verilog 代码功能: 多功能频率计,可测量信号的周期、脉冲宽度、占空比、频率,语言为verilog,quartus软件设计仿真…...

img标签src动态绑定资源失败问题
img标签src动态绑定资源失败问题 需要采用require的方式进行 在 Vue 中,require 是一个通用的模块加载函数,用于在运行时(客户端或服务器端)引入模块。它通常用于加载 JavaScript 文件、JSON 数据、静态资源等。 组件使用…...