首先我们要知道jwt的概念, json web token 用户client 与server端的认证,包含三部分: head payload signature。
详情看这个: https://jwt.io/ 或者 ruanyf的文章
直接上go的代码, utils/token.go:
package utils
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"time"
)
const (
KEY string = "JWT-ARY-STARK"
DEFAULT_EXPIRE_SECONDS int = 600 // default 10 minutes
)
type User struct {
Id string `json:"id"`
Name string `json:"json"`
}
// JWT -- json web token
// HEADER PAYLOAD SIGNATURE
// This struct is the PAYLOAD
type MyCustomClaims struct {
User
jwt.StandardClaims
}
// update expireAt and return a new token
func RefreshToken(tokenString string)(string, error) {
// first get previous token
token, err := jwt.ParseWithClaims(
tokenString,
&MyCustomClaims{},
func(token *jwt.Token)(interface{}, error) {
return []byte(KEY), nil
})
claims, ok := token.Claims.(*MyCustomClaims)
if !ok || !token.Valid {
return "", err
}
mySigningKey := []byte(KEY)
expireAt := time.Now().Add(time.Second * time.Duration(DEFAULT_EXPIRE_SECONDS)).Unix()
newClaims := MyCustomClaims{
claims.User,
jwt.StandardClaims{
ExpiresAt: expireAt,
Issuer: claims.User.Name,
IssuedAt: time.Now().Unix(),
},
}
// generate new token with new claims
newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
tokenStr, err := newToken.SignedString(mySigningKey)
if err != nil {
fmt.Println("generate new fresh json web token failed !! error :", err)
return "" , err
}
return tokenStr, err
}
func ValidateToken(tokenString string) error {
token, err := jwt.ParseWithClaims(
tokenString,
&MyCustomClaims{},
func(token *jwt.Token)(interface{}, error) {
return []byte(KEY), nil
})
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.User, claims.StandardClaims.ExpiresAt)
fmt.Println("token will be expired at ", time.Unix(claims.StandardClaims.ExpiresAt, 0))
} else {
fmt.Println("validate tokenString failed !!!",err)
return err
}
return nil
}
func GenerateToken(expiredSeconds int) (tokenString string) {
if expiredSeconds == 0 {
expiredSeconds = DEFAULT_EXPIRE_SECONDS
}
// Create the Claims
mySigningKey := []byte(KEY)
expireAt := time.Now().Add(time.Second * time.Duration(expiredSeconds)).Unix()
fmt.Println("token will be expired at ", time.Unix(expireAt, 0) )
// pass parameter to this func or not
user := User{"007", "Kev"}
claims := MyCustomClaims{
user,
jwt.StandardClaims{
ExpiresAt: expireAt,
Issuer: user.Name,
IssuedAt: time.Now().Unix(),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenStr, err := token.SignedString(mySigningKey)
if err != nil {
fmt.Println("generate json web token failed !! error :", err)
}
return tokenStr
}
// return this result to client then all later request should have header "Authorization: Bearer "
func getHeaderTokenValue(tokenString string) string {
//Authorization: Bearer
return fmt.Sprintf("Bearer %s", tokenString)
}
下一步我们给beego添加一个过滤器,假定:login接口返回给client 一个token,后续所有的请求都会带上这个token:
var FilterToken = func(ctx *context.Context) {
logs.Info("current router path is ", ctx.Request.RequestURI)
if ctx.Request.RequestURI != "/login" && ctx.Input.Header("Authorization") == "" {
logs.Error("without token, unauthorized !!")
ctx.ResponseWriter.WriteHeader(401)
ctx.ResponseWriter.Write([]byte("no permission"))
}
if ctx.Request.RequestURI != "/login" && ctx.Input.Header("Authorization") != "" {
token := ctx.Input.Header("Authorization")
token = strings.Split(token, "")[1]
logs.Info("curernttoken: ", token)
// validate token
// invoke ValidateToken in utils/token
// invalid or expired todo res 401
}
}
到这一步就完成了,不一定是beego可以是其他web框架都能使用utils/token.go里面的方法。