golang之JWT与session


由于目前JWT在验证权限方面是主流,因此重点介绍JWT

session和JWT是干啥的?

由于http连接是无状态的,用户登录后,请求结束,立刻断开连接,登录状态并不会保留,用户想要进行操作,服务器就必须对用户进行权限验证,session和JWT的本质,都是服务器在收到用户登录请求的时候,颁发给客户端一个token(令牌)(其实就是一个字符串而已),这个令牌一定和userID有一一对应的关系,客户端下次发请求的时候,携带这个令牌,服务端通过对令牌进行验证,可以知道发请求的到底是哪一个用户。
session通过查token的映射表找到userID,jwt通过解密token找到userID。

session

session是一种以seesionID作为token,颁发给客户端的验证方式,缺点是服务器必须维护一张以sessionID作为key的表,每次客户端的请求都要查这张表

JWT

JWT有三个部分,头部,载荷和签名
示例:
eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzM3ODU4NjYsImlhdCI6MTYzMzY5OTQ2NiwiaXNzIjoiYXV0aCIsInN1YiI6IjYxNWQ0ODlmMjVlZWExZmVlOWVlNjFmYiJ9.JSOrJ46Ynm9JLesnTuiuLMaqLTqN1-VZVzUHi1FqpNnYJxQ9KbH70w08tpYFG8dMXOCRyuuPEUKQmA4STSQBytchU4fgzVv0ow4ItEIVT2Masr7jslCu8skLNdyfHp50chIyA9mPc9dyouQIZX3KJ3sItJ3PiDWG3AVf8J86_SK-VYfUgfEYfRkXbQ21kFOTNTh3_UVIN4X8Z_VuuxVScs2XkRglFDsIvOknqfBw4paQFeItbvU-sYeSbKPWzi1PLb2XCKHmRj3-2T3lMTvgKfQM8uTheEtWydS-64PKj0WXbC-3riLgCEgYX6Zsk1uqRrP_oKbIMZheJ8CRS1JXyQ这里的头部和载荷都是base64编码的,也就是不加密的,只有签名部分是加密的。
签名部分经常用的就是两种:
对称加密:HS256、HS512
非对称加密:RS256、RS512
这里的RS加密因为加密用私钥,解密用公钥,公钥泄漏也没问题,因此比HS的安全性更高。
HS加解密用一个公钥,不过如果对网站的安全性要求没那么高,使用公钥加解密也没什么问题
payload部分官方的字段如下,我们也可以自定义字段:
这里的exp字段是必须要设置的,否则token的过期时间将不可控,有极大的危险

iss (issuer):签发人
sub (subject):主题
aud (audience):受众
exp (expiration time):过期时间
nbf (Not Before):生效时间,在此之前是无效的
iat (Issued At):签发时间
jti (JWT ID):编号

JWT的演示网站:
jwt.io

JWT是需要生成密钥的,这里推荐一个RSA密钥生成网站:
https://cryptotools.net/

golang的JWT操作

使用的库为jwt-go

加密(签名)(生成token)部分

生成JWT的类:

package token

import (
	"crypto/rsa"
	"github.com/dgrijalva/jwt-go"
	"time"
)

type JWTTokenGen struct {
	privateKey *rsa.PrivateKey
	issuer string
	nowFunc func() time.Time
}

func NewJWTTokenGen(issuer string, privateKey *rsa.PrivateKey) *JWTTokenGen {
	return &JWTTokenGen{
		issuer:  issuer,
		nowFunc: time.Now,
		privateKey: privateKey,
	}
}

func (t *JWTTokenGen) GenerateToken(accountID string, expire time.Duration) (string,error){
	nowSec := t.nowFunc().Unix()
	tkn := jwt.NewWithClaims(jwt.SigningMethodRS512, jwt.StandardClaims{
		ExpiresAt: nowSec + int64(expire.Seconds()),
		IssuedAt:  nowSec,
		Issuer:    t.issuer,
		Subject:   accountID,
	})
	return tkn.SignedString(t.privateKey)
}

生成rsa.privatekey类,传入JWTTokenGen

	pkBytes, err := ioutil.ReadAll(file)
	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(pkBytes))

解密部分(验证token,解析出userID)

验证类

package token

import (
	"crypto/rsa"
	"fmt"

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

// JWTTokenVerifier verifies jwt access tokens.
type JWTTokenVerifier struct {
	PublicKey *rsa.PublicKey
}

// Verify verifies a token and returns account id.
func (v *JWTTokenVerifier) Verify(token string) (string, error) {
	t, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return v.PublicKey, nil
		})

	if err != nil {
		return "", fmt.Errorf("cannot parse token: %v", err)
	}

	if !t.Valid {
		return "", fmt.Errorf("token not valid")
	}

	clm, ok := t.Claims.(*jwt.StandardClaims)
	if !ok {
		return "", fmt.Errorf("token claim is not StandardClaims")
	}

	if err := clm.Valid(); err != nil {
		return "", fmt.Errorf("claim not valid: %v", err)
	}

	return clm.Subject, nil
}

生成rsa.PublicKey

	pubKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(publicKey))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值