一。token、cookie、session的區別
1。cookie
Cookie總是保存在客戶端中,按在客戶端中的存儲位置,可分為內存Cookie和硬盤Cookie。 內存Cookie由瀏覽器維護,保存在內存中,瀏覽器關閉后就消失了,其存在時間是短暫的。
硬盤Cookie保存在硬盤里,有一個過期時間,除非用戶手工清理或到了過期時間,硬盤Cookie不會被刪除,其存在時間是長期的。
所以,按存在時間,可分為非持久Cookie和持久Cookie。 cookie 是一個非常具體的東西,指的就是瀏覽器里面能永久存儲的一種數據,僅僅是瀏覽器實現的一種數據存儲功能。 cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以key-value形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給服務器。
由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁盤空間,所以每個域的cookie數量是有限的。
2。session
session 從字面上講,就是會話。這個就類似於你和一個人交談,你怎么知道當前和你交談的是張三而不是李四呢?對方肯定有某種特征(長相等)表明他就是張三。
session 也是類似的道理,服務器要知道當前發請求給自己的是誰。為了做這種區分,服務器就要給每個客戶端分配不同的“身份標識”,
然后客戶端每次向服務器發請求的時候,都帶上這個“身份標識”,服務器就知道這個請求來自於誰了。至於客戶端怎么保存這個“身份標識”,
可以有很多種方式,對於瀏覽器客戶端,大家都默認采用 cookie 的方式。
服務器使用session把用戶的信息臨時保存在了服務器上,用戶離開網站后session會被銷毀。這種用戶信息存儲方式相對cookie來說更安全,
可是session有一個缺陷:如果web服務器做了負載均衡,那么下一個操作請求到了另一台服務器的時候session會丟失。
3。token
token的意思是“令牌”,是用戶身份的驗證方式.
最簡單的token組成:
【1】uid(用戶唯一的身份標識)
【2】time(當前時間的時間戳)
【3】sign(簽名,由token的前幾位+鹽以哈希算法壓縮成一定長的十六進制字符串,
可以防止惡意第三方拼接token請求服務器)。還可以把不變的參數也放進token,避免多次查庫 這里的token是指SON Web Token
用戶注冊之后, 服務器生成一個 JWT token返回給瀏覽器, 瀏覽器向服務器請求數據時將 JWT token 發給服務器,
服務器用 signature 中定義的方式解碼
WT 獲取用戶信息.
一個 JWT token包含3部分:
【1】header: 告訴我們使用的算法和 token 類型
【2】Payload: 必須使用 sub key 來指定用戶 ID, 還可以包括其他信息比如 email, username 等.
【3】Signature: 用來保證 JWT 的真實性. 可以使用不同算法
二。jwt(json web token)權限驗證
完整代碼:

1 package main 2 3 import ( 4 "log" 5 "net/http" 6 "github.com/codegangsta/negroni" 7 "encoding/json" 8 "fmt" 9 "strings" 10 "github.com/dgrijalva/jwt-go" 11 "time" 12 "github.com/dgrijalva/jwt-go/request" 13 ) 14 15 /** 16 說明: 17 客戶端通過在request對象header里添加token參數,發送到服務端。 18 服務端再拿出token進行比對。 19 token的第一次產生是發生在login檢查賬戶存在並且正確之后,為該用戶賦予一塊令牌(加密字符串) 20 並將token放入response的header里。客戶端登陸成功后,從response里取出token。並在以后操作request請求。 21 都保持在header里添加該段令牌,令牌有效期失效后,只有重新login,才能獲取新的令牌。 22 */ 23 const ( 24 //SecretKey = "welcome to wangshubo's blog" 25 SecretKey = "I have login" 26 ) 27 28 func fatal(err error) { 29 if err != nil { 30 log.Fatal(err) 31 } 32 } 33 34 type UserCredentials struct { 35 Username string `json:"username"` 36 Password string `json:"password"` 37 } 38 39 type User struct { 40 ID int `json:"id"` 41 Name string `json:"name"` 42 Username string `json:"username"` 43 Password string `json:"password"` 44 } 45 46 type Response struct { 47 Data string `json:"data"` 48 } 49 50 type Token struct { 51 Token string `json:"token"` 52 } 53 54 func StartServer() { 55 56 http.HandleFunc("/login", LoginHandler) 57 58 http.Handle("/resource", negroni.New( 59 negroni.HandlerFunc(ValidateTokenMiddleware), 60 negroni.Wrap(http.HandlerFunc(ProtectedHandler)), 61 )) 62 63 log.Println("Now listening...") 64 http.ListenAndServe(":8080", nil) 65 } 66 67 func main() { 68 StartServer() 69 } 70 71 func ProtectedHandler(w http.ResponseWriter, r *http.Request) { 72 73 response := Response{"Gained access to protected resource !"} 74 JsonResponse(response, w) 75 76 } 77 78 //服務端生成token,並放入到response的header 79 /** 80 JWT由三部份組成: 81 * Header:頭部 (對應:Header) 82 * Claims:聲明 (對應:Payload) 83 * Signature:簽名 (對應:Signature) 84 */ 85 func LoginHandler(w http.ResponseWriter, r *http.Request) { 86 87 var u *User=new(User) 88 89 var user UserCredentials 90 91 err := json.NewDecoder(r.Body).Decode(&user) 92 93 if err != nil { 94 w.WriteHeader(http.StatusForbidden) 95 fmt.Fprint(w, "Error in request") 96 return 97 } 98 99 //驗證是身份:若用戶是someone,則生成token 100 if strings.ToLower(user.Username) != "someone" { 101 if user.Password != "p@ssword" { 102 w.WriteHeader(http.StatusForbidden) 103 fmt.Println("Error logging in") 104 fmt.Fprint(w, "Invalid credentials") 105 return 106 } 107 } 108 109 //1。生成token 110 token := jwt.New(jwt.SigningMethodHS256) 111 claims := make(jwt.MapClaims) 112 //2。添加令牌關鍵信息 113 //添加令牌期限 114 claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix() 115 claims["iat"] = time.Now().Unix() 116 claims["id"]=u.ID 117 claims["userName"]=u.Username 118 claims["password"]=u.Password 119 token.Claims = claims 120 121 fmt.Println(claims) 122 123 if err != nil { 124 w.WriteHeader(http.StatusInternalServerError) 125 fmt.Fprintln(w, "Error extracting the key") 126 fatal(err) 127 } 128 129 //獲取令牌 130 tokenString, err := token.SignedString([]byte(SecretKey)) 131 if err != nil { 132 w.WriteHeader(http.StatusInternalServerError) 133 fmt.Fprintln(w, "Error while signing the token") 134 fatal(err) 135 } 136 137 //2。將生成的token放入到header 138 response := Token{tokenString} 139 JsonResponse(response, w) 140 141 } 142 143 //驗證Token 144 func ValidateTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 145 token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, 146 func(token *jwt.Token) (interface{}, error) { 147 return []byte(SecretKey), nil 148 }) 149 150 if err == nil { 151 if token.Valid { 152 next(w, r) 153 } else { 154 w.WriteHeader(http.StatusUnauthorized) 155 fmt.Fprint(w, "Token is not valid") 156 } 157 } else { 158 w.WriteHeader(http.StatusUnauthorized) 159 fmt.Fprint(w, "Unauthorized access to this resource") 160 } 161 162 } 163 164 func JsonResponse(response interface{}, w http.ResponseWriter) { 165 json, err := json.Marshal(response) 166 if err != nil { 167 http.Error(w, err.Error(), http.StatusInternalServerError) 168 return 169 } 170 w.WriteHeader(http.StatusOK) 171 w.Header().Set("Content-Type", "application/json") 172 w.Write(json) 173 }
通過postman進行驗證:
Step1:發送登錄請求
Step2:使用服務端返回客戶端的token去驗證有效性(根據獲得的token進行get請求)
參考博客:https://blog.csdn.net/wangshubo1989/article/details/74529333