@@ -1,58 +0,0 @@ 04.通过jwt基于token实现登陆认证 | 凤凰涅槃进阶之路

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

Abel sun2023年1月6日约 1113 字大约 4 分钟

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

三个常见概念:

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
}

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

image-20200609150621884

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

image-20200609151000783

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.9.1