Golang JWT

Golang JWT
http的无状态催生了cookie 和seesion
Cookie
  • cookie是保存在客户端中的客户端相关的用户信息:用户名密码等可以用于服务端的二次验证,初始访问时的客户端请求不携带cookie,服务端会为其添加对应的cookie字段二次访问时cookie和客户端请求一起发送到服务端
    • Cookie分为会话Cookie和持久Cookie:
      • 会话Cookie不保存到硬盘上,生命周期到浏览器关闭
      • 持久Cookie保存到磁盘上,生存周期由设置的MaxAge决定
Session
  • Session是服务端保存的客户端的操作历史,使用唯一的Session-id来标识客户端和服务器之间的Session会话
    • Session通过客户端Cookie保存Session-id,cookie因为所有的记录保存在客户端所以有安全隐患
    • 对于做了负载均衡的session服务访问容易出现在一个服务器上的session在其它服务器上不存在因此需要同步管理
Token
  •   Token是对用户身份的标识信息:一般是用户标识和时间戳签名等组成的哈希后的十六进制字符串
    
JWT(Json Web Token)
*       通信流程:用户向服务器发送注册信息后服务器生成JWT给客户端,客户端由此在下一次访问时将JWT带上,服务器使用特定的signature中定义的解码方式将其解码
*       JWT Token包含三个部分
        -header:算法和token类型的标识
        -Payload: 必须使用 sub key 来指定用户 ID, 还可以包括其他信息比如 email, username 等.主要是为了承载内容而存在
        规范的字段:
        iss: jwt签发者
        sub: jwt所面向的用户
        aud: 接收jwt的一方
        exp: jwt的过期时间,这个过期时间必须要大于签发时间
        nbf: 定义在什么时间之前,该jwt都是不可用的.
        iat: jwt的签发时间
        jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
        -Signature: 用来保证 JWT 的真实性. 可以使用不同算法
*       JWT就是:
        加密算法(
         base64UrlEncode(header) + "." +
         base64UrlEncode(payload),
         secret)其中的secrete是一个随机的字符串
```bash
token:=jwt.New(jwt.SigningMethodHS256)//设置加密类型
claims := token.Claims.(jwt.mMapClais)
claims["name"] = "hades"
claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
token.Claims=claims
//
t, err := token.SignedString([]byte("secret"))//将secret加入
/*
也可使用如下构造
token:=jwt.NewWithClaims(jwt.SigningMethodHS256,jwt.MapClaims{
		"username":user.UserName,
		"password":user.PassWord,
	})
reply.Token,err=token.SignedString([]byte("secret"))
*/
var jwtSecret = []byte(setting.JwtSecret)
type Claims struct {
    Username string `json:"username"`
    Password string `json:"password"`
    jwt.StandardClaims
}
func GenerateToken(username, password string) (string, error) {
    nowTime := time.Now()
    expireTime := nowTime.Add(3 * time.Hour)//为token添加过期时间
    claims := Claims{
        username,
        password,
        jwt.StandardClaims {
            ExpiresAt : expireTime.Unix(),
            Issuer : "gin-blog",
        },
    }
    tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    token, err := tokenClaims.SignedString(jwtSecret)
    return token, err
}
func ParseToken(token string) (*Claims, error) {
    tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        return jwtSecret, nil
    })
    if tokenClaims != nil {
        if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
            return claims, nil
        }
    }
    return nil, err
}

其中
func(token *jwt.Token) (interface{}, error){

}
属于固定格式的函数编写
func (m MapClaims) Valid() 验证基于时间的声明exp, iat, nbf,注意如果没有任何声明在令牌中,仍然会被认为是有效的。并且对于时区偏差没有计算方法
简单实例:

package main

import (
	"log"
	"net/http"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

func PostInfo(context *gin.Context) {
	context.Request.ParseForm()
	log.Printf("name:%v\n", context.PostForm("name"))
	log.Printf("id:%v\n", context.DefaultPostForm("id", "123456"))
	log.Println("Body:", context.Request.Form)
	log.Println("Query name:", context.Query("name")) //依赖于URL后面的参数
	log.Println("Query info:", context.DefaultQuery("info", "vvvvery "))
}

func main() {
	app := gin.Default() 
	app.GET("/auth", Auth)
	app.GET("authtest", AuthTest)
	app.Run(":8080")
}

func GetToken(username, password string) string {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": username,
		"password": password,
	})
	res, _ := token.SignedString([]byte("secret"))
	return res
}

func Auth(context *gin.Context) {
	username := context.Query("username")
	password := context.Query("password")
	context.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"token":  GetToken(username, password),
	})

}
func AuthTest(context *gin.Context) {
	username := context.Query("username")
	password := context.Query("password")
	token := context.Query("token")
	/*
	从请求URL中获取对应的参数
	*/
	if token == "" {
		context.JSON(http.StatusBadRequest, gin.H{
			"status": http.StatusBadRequest,
			"info":   "Access Permision Denied",
		})
		return
	//直接在验证是生成一个token很不方便,应当使用像redis这样的数据库存放所有的token,比较好的是redis还可以设置过期时间
	} else if token == GetToken(username, password) {
		context.JSON(http.StatusOK, gin.H{
			"status": http.StatusOK,
			"info":   "Access Success",
		})
		return
	} else {
		context.JSON(http.StatusBadRequest, gin.H{
			"status": http.StatusBadRequest,
			"info":   "tocken error:Access Permision Denied",
		})
		return
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值