二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Shell编程

  • Go编程笔记

  • 前端编程笔记

  • Go学习笔记

    • 基础部分

    • web框架

      • 标准库template学习入门
      • gin框架学习入门
      • 解决前端调用后端跨域问题
      • 通过jwt基于token实现登陆认证
      • orm框架

    • Vue-21年学习笔记

    • Vue-22年重学笔记

    • 编程世界
    • Go学习笔记
    • web框架
    二丫讲梵
    2021-07-10
    目录

    通过jwt基于token实现登陆认证

    文章发布较早,内容可能过时,阅读注意甄别。

    三个常见概念:

    # Cookie

    Cookie 总是保存在客户端中,按在客户端中的存储位置,可分为内存 Cookie 和硬盘 Cookie。

    内存 Cookie 由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘 Cookie 保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘 Cookie 不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久 Cookie 和持久 Cookie。

    cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

    cookie 由服务器生成,发送给浏览器,浏览器把 cookie 以 key-value 形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该 cookie 发送给服务器。由于 cookie 是存在客户端上的,所以浏览器加入了一些限制确保 cookie 不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的 cookie 数量是有限的。

    # Session

    session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

    session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

    服务器使用 session 把用户的信息临时保存在了服务器上,用户离开网站后 session 会被销毁。这种用户信息存储方式相对 cookie 来说更安全,可是 session 有一个缺陷:如果 web 服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候 session 会丢失。

    # Token

    token 的意思是“令牌”,是用户身份的验证方式,最简单的 token 组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由 token 的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接 token 请求服务器)。还可以把不变的参数也放进 token,避免多次查库

    这里的 token 是指 SON Web Token: JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS).

    这里使用 gin 框架,结合 jwt 来做一个小 demo。

    package main
    
    import (
    	"fmt"
    	"net/http"
    	"time"
    
    	"github.com/dgrijalva/jwt-go"
    	"github.com/gin-gonic/gin"
    )
    
    //自定义一个字符串
    var jwtkey = []byte("eryajf.net")
    var str string
    
    type Claims struct {
    	UserId uint
    	jwt.StandardClaims
    }
    
    func main() {
    	r := gin.Default()
    	r.GET("/set", setting)
    	r.GET("/get", getting)
    	//监听端口默认为8080
    	r.Run(":8080")
    }
    
    //颁发token
    func setting(ctx *gin.Context) {
    	expireTime := time.Now().Add(7 * 24 * time.Hour)
    	claims := &Claims{
    		UserId: 2,
    		StandardClaims: jwt.StandardClaims{
    			ExpiresAt: expireTime.Unix(), //过期时间
    			IssuedAt:  time.Now().Unix(),
    			Issuer:    "127.0.0.1",  // 签名颁发者
    			Subject:   "user token", //签名主题
    		},
    	}
    	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    	// fmt.Println(token)
    	tokenString, err := token.SignedString(jwtkey)
    	if err != nil {
    		fmt.Println(err)
    	}
    	// str = tokenString
    	ctx.JSON(http.StatusOK, gin.H{"code": 200, "token": tokenString})
    }
    
    //解析token
    func getting(ctx *gin.Context) {
    	tokenString := ctx.GetHeader("Authorization") //从header中取Authorization这个key,再与刚刚的token进行比对
    	// 先判断取到的是否为空,为空则跳出
    	if tokenString == "" {
    		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
    		ctx.Abort()
    		return
    	}
    	// 再来解析token,解析失败则跳出
    	token, claims, err := ParseToken(tokenString)
    	if err != nil || !token.Valid {
    		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
    		ctx.Abort()
    		return
    	}
    	// 最后成功了
    	ctx.JSON(http.StatusOK, gin.H{"code": 200, "id": claims.UserId, "msg": "认证通过"})
    
    }
    
    // ParseToken 解析token
    func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
    	Claims := &Claims{}
    	token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) {
    		return jwtkey, nil
    	})
    	return token, Claims, err
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    然后利用 postman 进行访问,先生成一个 token。

    image-20200609150621884

    接着拿上这个 token 再次 get 请求,可以查看效果,为空或者错误都将访问失败。

    image-20200609151000783

    微信 支付宝
    上次更新: 2024/07/04, 22:40:37
    解决前端调用后端跨域问题
    gorm框架入门

    ← 解决前端调用后端跨域问题 gorm框架入门→

    最近更新
    01
    记录二五年五一之短暂回归家庭
    05-09
    02
    学习周刊-总第210期-2025年第19周
    05-09
    03
    学习周刊-总第209期-2025年第18周
    05-03
    更多文章>
    Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式