JWT是json web token縮寫。它將用戶信息加密到token里,服務器不保存任何用戶信息。服務器通過使用保存的密鑰驗證token的正確性,只要正確即通過驗證。
JWT 和sessions 不同 session是存儲在服務器的,每次只給客戶端返回sessionid,客戶端每次請求時帶上sessionid即可。
但是,有多台服務器時就會出現一些麻煩,需要同步多台服務器信息,session就不好處理了。因為session是保存在服務器的,會出現A服務器能獲取信息,B服務器身份信息無法通過。所以JWT就能很好的解決這個問題。服務器不需要保存信息,只需要保存加密用的secret,在用戶登陸后將JWT加密生成token並發送給客戶端,由客戶端存儲,客戶端每次請求帶上token。讓服務器進行解析並驗證。
JWT構成
一、Header (頭部)
Jwt的頭部承載兩部分信息:
聲明類型,這里是jwt
聲明加密的算法 通常直接使用 HMAC SHA256
二、 Playload(載荷又稱為Claim)
playload可以填充兩種類型數據
1.標准中注冊的聲明:
iss: 簽發者
sub: 面向的用戶
aud: 接收方
exp: 過期時間 nbf: 生效時間 iat: 簽發時間 jti: 唯一身份標識
2.自定義數據
三、Signature(簽名)
簽名的算法:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
代碼實現
下載
go get -u "github.com/dgrijalva/jwt-go"
引入
import ( "errors" "fmt" "time" "github.com/dgrijalva/jwt-go" )
定義結構體
type Userinfo struct { Username string `json:"username"` Password string `json:"password"` }
1、生成token
func Macke(user *Userinfo) (token string, err error) { //生成jwt claims := jwt.MapClaims{ //創建一個自己的聲明 "name": user.Username, "pwd": user.Password, "iss": "lva", "nbf": time.Now().Unix(), "exp": time.Now().Add(time.Second * 4).Unix(), "iat": time.Now().Unix(), }
then := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
fmt.Println(then) //打印&{ 0xc0000040a8 map[alg:HS256 typ:JWT] map[exp:1637212218 iat:1637212214 iss:lvjianhua name:zhansan nbf:1637212214 pwd:pwd] false}
token, err = then.SignedString([]byte("gettoken"))
return }
2、解析token
func secret() jwt.Keyfunc { //按照這樣的規則解析 return func(t *jwt.Token) (interface{}, error) { return []byte("gettoken"), nil } } //解析token func ParseToken(token string) (user *Userinfo, err error) { user = &Userinfo{} tokn, _ := jwt.Parse(token, secret()) claim, ok := tokn.Claims.(jwt.MapClaims) if !ok { err = errors.New("解析錯誤") return } if !tokn.Valid { err = errors.New("令牌錯誤!") return } fmt.Println(claim) user.Username = claim["name"].(string) //強行轉換為string類型 user.Password = claim["pwd"].(string) //強行轉換為string類型 return }
3、實戰使用
package main import ( "fmt" token "main/jwtset" ) func main() { var use = token.Userinfo{"zhansan", "pwd"} tkn, _ := token.Macke(&use) fmt.Println("_____", tkn) // time.Sleep(time.Second * 8)超過時間打印令牌錯誤 user, err := token.ParseToken(tkn) if err != nil { fmt.Println(err) } fmt.Println(user.Username) }
用戶請求時帶上token,服務器解析token后可以獲得其中的用戶信息,如果token有任何改動,都無法通過驗證.
內容摘抄來自:https://www.jianshu.com/p/b4e0744b44e0/