文章目录

  • Golang jwt跨域鉴权
    • jwt介绍
      • JWT 到底是什么?
      • JWT 和 OAuth
      • 选择签名方法
      • 签名方法和密钥类型
    • 安装jwt
    • 简单使用
      • 生成JWT
      • 解析jwt
      • 测试:生成token并解析token
    • jwt在项目中的使用
      • 第一步:在一个go文件中,写生成jwt和解析jwt的方法,方便调用
      • 第二步:登陆的时候生成token
      • 第三步:在控制器中写一个go文件,`JWTAuthMiddleware` 基于JWT的认证中间件
      • 第四部:登陆验证token

Golang jwt跨域鉴权

JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0业务场景下。

jwt介绍

官网:https://jwt.io/

JWT 到底是什么?

简而言之,jwt是一个签名的 JSON 对象,可以做一些有用的事情(例如,身份验证)。它通常用于BearerOauth 2 中的令牌。令牌由三部分组成,由.'s 分隔。前两部分是 JSON 对象,已经过base64url编码。最后一部分是签名,以同样的方式编码。

第一部分称为标题。它包含验证最后一部分签名的必要信息。例如,使用哪种加密方法进行签名以及使用了什么密钥。

中间的部分是有趣的部分。它称为声明,包含您关心的实际内容。有关保留密钥和添加自己的正确方法的信息,请参阅RFC 。

JWT 和 OAuth

值得一提的是,OAuth 和 JWT 不是一回事。JWT 令牌只是一个签名的 JSON 对象。它可以在任何有用的地方使用。但是,存在一些混淆,因为 JWT 是 OAuth2 身份验证中最常见的不记名令牌类型。

不用太深入,这里是对这些技术交互的描述:

  • OAuth 是一种允许身份提供者与用户登录的服务分开的协议。例如,每当您使用 Facebook 登录不同的服务(Yelp、Spotify 等)时,您都在使用 OAuth。
  • OAuth 定义了几个用于传递身份验证数据的选项。一种流行的方法称为“不记名令牌”。不记名令牌只是一个字符串,只能由经过身份验证的用户持有。因此,只需出示此令牌即可证明您的身份。您可能可以从这里得出为什么 JWT 可能会成为一个好的不记名令牌。
  • 因为不记名令牌用于身份验证,所以对它们保密很重要。这就是使用不记名令牌的交易通常通过 SSL 发生的原因。

选择签名方法

有几种可用的签名方法,您可能应该花时间了解各种选项,然后再选择一种。主要的设计决策很可能是对称的还是非对称的。

对称签名方法(例如 HSA)仅使用一个密钥。这可能是最简单的签名方法,因为任何[]byte都可以用作有效的秘密。它们在计算上的使用速度也略快一些,尽管这很少有关系。当令牌的生产者和消费者都受信任,甚至是同一个系统时,对称签名方法效果最好。由于相同的密钥用于签名和验证令牌,因此您无法轻松分发密钥以进行验证。

非对称签名方法(例如 RSA)使用不同的密钥来签名和验证令牌。这使得使用私钥生成令牌成为可能,并允许任何消费者访问公钥进行验证。

签名方法和密钥类型

jwt-go库支持 JWT 的解析和验证以及生成和签名。当前支持的签名算法是 HMAC SHA、RSA、RSA-PSS 和 ECDSA

每个签名方法都需要不同的对象类型作为其签名密钥。有关详细信息,请参阅软件包文档。以下是最常见的:

  • HMAC 签名方法( HS256, HS384, HS512)[]byte需要用于签名和验证的值
  • RSA 签名方法( , RS256, RS384)RS512期望*rsa.PrivateKey用于签名和*rsa.PublicKey验证
  • ECDSA 签名方法( , ES256, ES384)ES512期望*ecdsa.PrivateKey用于签名和*ecdsa.PublicKey验证

安装jwt

go get github.com/dgrijalva/jwt-go

简单使用

生成JWT

type MyClaims struct {//除了满足下面的Claims,还需要以下用户信息Username string `json:"username"`Password string `json:"password"`//jwt中标准的Claimsjwt.StandardClaims
}// 使用指定的 secret 签名声明一个 key ,便于后续获得完整的编码后的字符串token
var key = []byte("secret")//GenToken 生成token的方法
func GenToken(username string, password string) (string, error) {//创建一个我们自己的声明c := MyClaims{username, //自定义字段password,jwt.StandardClaims{ExpiresAt: time.Now().Add(time.Hour * 2).Unix(), //过期时间Issuer:    "Psych",                              //签发人},}//使用指定的签名方法创建签名对象//这里使用HS256加密算法token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)//注意这个地方的 key 一定要是字节切片不能是字符串return token.SignedString(key)
}

解析jwt

//ParseToken 解析token的方法
func ParseToken(tokenString string) (*MyClaims, error) {//解析tokentoken, err := jwt.ParseWithClaims(tokenString, &MyClaims{},func(token *jwt.Token) (i interface{}, err error) {return key, nil})if err != nil {return nil, err}if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { //校验tokenreturn claims, nil}return nil, errors.New("invalid token")
}

测试:生成token并解析token

func main() {//生成tokentoken, err := GenToken("Psych", "123456")if err != nil {panic(err)}fmt.Printf("token: %v\n", token)fmt.Println("----------------------")//解析tokenparseToken, err := ParseToken(token)if err != nil {panic(err)}fmt.Printf("parseToken.UserName: %v\n", parseToken.Username)fmt.Printf("parseToken.Password: %v\n", parseToken.Password)
}

运行结果:

[Running] go run "e:\golang开发学习\go_pro\main.go"
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlBzeWNoIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJleHAiOjE2NjI1MzQ5MTEsImlzcyI6IlBzeWNoIn0.hsqMq08NB2uz5OSMXB5KT-77WlirvcSX8kgtyWIVEP0
----------------------
parseToken.UserName: Psych
parseToken.Password: 123456[Done] exited with code=0 in 1.572 seconds

jwt在项目中的使用

第一步:在一个go文件中,写生成jwt和解析jwt的方法,方便调用

package jwtimport ("errors""time""github.com/dgrijalva/jwt-go"
)//载荷
type Customclaims struct {Empname string `json:"empname"`Phone   string `json:"phone"`Role    string `json:"role"`jwt.StandardClaims
}// MyClaims 自定义声明结构体并内嵌jwt.StandardClaims
// jwt包自带的jwt.StandardClaims只包含了官方字段
// 我们这里需要额外记录一个UserID字段,所以要自定义结构体
// 如果想要保存更多信息,都可以添加到这个结构体中
type MyClaims struct {UserName string `json:"user_name"`jwt.StandardClaims
}var mySecret = []byte("呼哧呼哧")func keyFunc(_ *jwt.Token) (i interface{}, err error) {return mySecret, nil
}const TokenExpireDuration = time.Hour * 24 * 365// GenToken 生成access token 和 refresh token
func GenToken(userName string) (aToken, rToken string, err error) {// 创建一个我们自己的声明c := MyClaims{userName, // 自定义字段jwt.StandardClaims{ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间Issuer:    "personal-blog",                            // 签发人},}// 加密并获得完整的编码后的字符串tokenaToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString(mySecret)// refresh token 不需要存任何自定义数据rToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{ExpiresAt: time.Now().Add(time.Second * 30).Unix(), // 过期时间Issuer:    "personal-blog",                         // 签发人}).SignedString(mySecret)// 使用指定的secret签名并获得完整的编码后的字符串tokenreturn
}// ParseToken 解析JWT
func ParseToken(tokenString string) (claims *MyClaims, err error) {// 解析tokenvar token *jwt.Tokenclaims = new(MyClaims)token, err = jwt.ParseWithClaims(tokenString, claims, keyFunc)if err != nil {return}if !token.Valid { // 校验tokenerr = errors.New("invalid token")}return
}// RefreshToken 刷新AccessToken
func RefreshToken(aToken, rToken string) (newAToken, newRToken string, err error) {// 从旧access token中解析出claims数据    解析出payload负载信息var claims MyClaims_, err = jwt.ParseWithClaims(aToken, &claims, keyFunc)// 当access token是过期错误 并且 refresh token没有过期时就创建一个新的access tokenreturn GenToken(claims.UserName)}

第二步:登陆的时候生成token

//登录
func LoginHandler(c *gin.Context) {// 1.获取请求参数 2.校验数据有效性var L models.Usersif err := c.ShouldBindJSON(&L); err != nil {zap.L().Error("invalid params", zap.Error(err))ResponseErrorWithMsg(c, CodeInvalidParams, err.Error())return}var my models.Update_my//用户登录if err, a := mysql.Login(&L); err != nil {zap.L().Error("mysql.Login(&u) failed", zap.Error(err))ResponseError(c, CodeInvalidPassword)return} else {my = a}// 生成TokenaToken, rToken, _ := jwt.GenToken(L.UserName)ResponseSuccess(c, gin.H{"accessToken":  aToken,"refreshToken": rToken,"username":     L.UserName,"role":         L.Role,"realname":     my.Realname,"phone_number": my.PhoneNumber,"id_number":    my.IDNumber,})
}

第三步:在控制器中写一个go文件,JWTAuthMiddleware 基于JWT的认证中间件

package controllerimport ("Fever_backend/dao/mysql""Fever_backend/pkg/jwt""errors""fmt""go.uber.org/zap""net/http""strings""github.com/gin-gonic/gin"
)const (ContextUserNameKey = "userName"
)var (ErrorUserNotLogin = errors.New("当前用户未登录")
)// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {return func(c *gin.Context) {// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI// 这里假设Token放在Header的Authorization中,并使用Bearer开头// 这里的具体实现方式要依据你的实际业务情况决定authHeader := c.Request.Header.Get("Authorization")if authHeader == "" {ResponseErrorWithMsg(c, CodeInvalidToken, "请求头缺少Auth Token")c.Abort()return}// 按空格分割parts := strings.SplitN(authHeader, " ", 2)if !(len(parts) == 2 && parts[0] == "Bearer") {ResponseErrorWithMsg(c, CodeInvalidToken, "Token格式不对")c.Abort()return}// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它mc, err := jwt.ParseToken(parts[1])if err != nil {fmt.Println(err)ResponseError(c, CodeInvalidToken)c.Abort()return}// 将当前请求的username信息保存到请求的上下文c上c.Set(ContextUserNameKey, mc.UserName)c.Next() // 后续的处理函数可以用过c.Get("userID")来获取当前请求的用户信息}
}

第四部:登陆验证token

//这里只是举了个例,具体业务需要具体分析
//登录验证tokenv1.Use(controller.JWTAuthMiddleware()){//修改密码v1.POST("/change_password", controller.ChangePasswordHandler)//加权限v1.POST("/add_casbin", controller.AddCasbin)}

Go语言学习笔记——jwt跨域鉴权相关推荐

  1. Golang jwt跨域鉴权

    Golang jwt跨域鉴权 JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0 安装jwt ...

  2. LiveNVR传统IP摄像机接入-网页直播实现跨域鉴权

    LiveNVR如何实现跨域鉴权 LiveNVR提供简单的登录鉴权,客户端通过用户名密码登录成功后,服务端返回认证token的cookie, 后续的接口访问, 服务端从cookie读取token进行校验 ...

  3. 跨域学习笔记2--WebApi 跨域问题解决方案:CORS

    自己并不懂,在此先记录下来,留待以后学习... 正文 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题.本篇主要从实例的角度分享下CORS解决跨 ...

  4. Fiori学习笔记 - 服务跨域处理neo-app

    学习Fiori有一段时间了,今天详细了解了一下neo-app配置文件,特在此记录一下. Eclipse + SAP UI5插件开发是不需要neo-app配置文件的,这个文件主要是针对于Web IDE开 ...

  5. LiveGBS-GB28181流媒体服务如何实现跨域鉴权

    LiveGBS 实现了 GB28181 协议,能够接入各个厂家的监控设备和监控平台,实现统一管理,和 web 端无插件播放,同时支持手机.微信播放. LiveGBS 提供简单的登录鉴权,客户端通过用户 ...

  6. LiveGBS国标流媒体GB28181微信无插件直播如何实现跨域鉴权

    LiveGBS 实现了 GB28181 协议,能够接入各个厂家的监控设备和监控平台,实现统一管理,和 web 端无插件播放,同时支持手机.微信播放. LiveGBS 提供简单的登录鉴权,客户端通过用户 ...

  7. [UVMC]UVMC学习笔记之跨语言作用域的config操作

    UVMC学习笔记二 --- 跨语言作用域的config操作 前言:UVMC引入了特定的内存共享方法,可以在UVM/SystemVerilog与SystemC模块之间传递记名的半全局变量,在使用方式上类 ...

  8. 手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

    作者 | 写代码的明哥 来源 | Python编程时光 这篇文章本应该是属于 HTTP 里的一部分内容,但是我看内容也挺多的,就单独划分一篇文章来讲下. 什么是跨域请求 要明白什么叫跨域请求,首先得知 ...

  9. 梓益C语言学习笔记之链表&动态内存&文件

    梓益C语言学习笔记之链表&动态内存&文件 一.定义: 链表是一种物理存储上非连续,通过指针链接次序,实现的一种线性存储结构. 二.特点: 链表由一系列节点(链表中每一个元素称为节点)组 ...

最新文章

  1. Windows 7下Eclipse搭建Android开发环境
  2. okhttp上传文件结束后服务器才收到,okhttp3 Null Respone上传文件
  3. 如何在云服务器上安装vim(bash: vim :command not found)
  4. [转]史上最全的CSS hack方式一览
  5. 设置和使用地图的范围—ArcGIS API for JavaScript
  6. 语音识别技术突飞猛进
  7. 2020谷歌服务助手_华为mate30没法用谷歌?新加坡网友实测如何越过官方限制!...
  8. 如何使用TCPA300电流放大器和电流探头进行电流测试
  9. 计算机网络一般包括资源子网和什么两部分,一个计算机网络一般包括什么和通信子网两部分...
  10. 速卖通关键词挖掘工具_谷歌优化关键词挖掘工具大全
  11. python练习54:取一个整数a从右端开始的4〜7位
  12. java判断数的奇偶性_判断一个数的奇偶性
  13. 【BZOJ4484】【JSOI2015】最小表示(拓扑排序,bitset)
  14. 广告系统,业务与架构细节
  15. java excel 批注_Java 添加、读取和删除 Excel 批注的操作代码
  16. Qt 多显示器扩展模式
  17. win7提示盗版 且各种工具无法激活
  18. VUE基础、表达式和指令
  19. 二维超声速流——普朗特-迈耶稀疏波的流场CFD解(附完整代码)
  20. pgsql实现表字段自增——三步走

热门文章

  1. 最新2020JAVA社招面试问题总结
  2. oracle exadata celldisk 闪存盘受损导致性能下降
  3. 原生android pie壁纸,为你奉献极具设计感的壁纸 -- Evolve Wallpapers #Android
  4. nginx安装配置总结
  5. git基础教程(20) 从版本库删除文件git rm
  6. 关于多态三种基本形式
  7. FPGA接口_N25Q128型号的spi flash驱动verilog代码编写
  8. php版本下载,Windows版本PHP下载-PHP For Windows下载v7.4.13 官方最新版-西西软件下载...
  9. lvextend遇到的问题
  10. 评测三款最流行的epub阅读器(windows适用)