Go语言:JWT鉴权
JWT是什么
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
使用场景
- Authorization (授权) :这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
- Information Exchange (信息交换) :对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。
JWT和OAuth的区别
- OAuth2是一种授权框架 ,JWT是一种认证协议。
- 无论使用哪种方式切记用HTTPS来保证数据的安全性。
- OAuth2用在使用第三方账号登录的情况(比如使用weibo,qq,github登录某个app),而JWT是用在前后端分离,,需要简单的对后台API进行保护时使用。
Go语言使用JWT
Go语言中已实现多个可用JWT库,比较常用的有jwt-go、jwt-auth
两个:
-
jwt-go :Golang implementation of JSON Web Tokens (JWT)
go get github.com/dgrijalva/jwt-go
-
jwt-auth:JWT middleware for Golang http servers with many configuration options
go get github.com/adam-hanna/jwt-auth
jwt-go库
jwt-go创建Token对象有两种方法:New和NewWithClaims。前者使用库默认Claims,后者使用自定义Claims。自定义Claims继承jwt.StandardClaims
并添加需要的用户信息(示例所示)。
type Token struct {
Raw string // The raw token. Populated when you Parse a token
Method SigningMethod // The signing method used or to be used
Header map[string]interface{} // The first segment of the token
Claims Claims // The second segment of the token
Signature string // The third segment of the token. Populated when you Parse a token
Valid bool // Is the token valid? Populated when you Parse/Verify a token
}
// Create a new Token. Takes a signing method
func New(method SigningMethod) *Token {
return NewWithClaims(method, MapClaims{})
}
func NewWithClaims(method SigningMethod, claims Claims) *Token {
return &Token{
Header: map[string]interface{}{
"typ": "JWT",
"alg": method.Alg(),
},
Claims: claims,
Method: method,
}
}
示例(jwt-go):
package util
import (
"fmt"
"time"
"github.com/dgrijalva/jwt-go"
)
// Claims custom token
type Claims struct {
PlayerID int32 `json:"player_id"` // 玩家
Channel int32 `json:"channel"` // 渠道
Version int32 `json:"version"` // 版本
LoginType int32 `json:"login_type"` // 登录方式
jwt.StandardClaims
}
// CreateToken create token
func CreateToken(claims *Claims) (signedToken string, success bool) {
claims.ExpiresAt = time.Now().Add(time.Minute * 30).Unix()
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, err := token.SignedString([]byte("secret"))
if err != nil {
return
}
success = true
return
}
// ValidateToken validate token
func ValidateToken(signedToken string) (claims *Claims, success bool) {
token, err := jwt.ParseWithClaims(signedToken, &Claims{},
func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected login method %v", token.Header["alg"])
}
return []byte("secret"), nil
})
if err != nil {
return
}
claims, ok := token.Claims.(*Claims)
if ok && token.Valid {
success = true
return
}
return
}