token的使用場景,比如當服務端在多個地方,使用session就需要持久化……。
總的思路:用戶在客戶端(瀏覽器)中輸入用戶名和密碼,提交後發送到服務端,服務端驗證正確後,生成一個token,將token返回給用戶瀏覽器,瀏覽器記住這個token,下次訪問,攜帶這個token,服務端先取出這個token,驗證正確後放行。
問題:
- 因爲服務端不像session那樣負責保存token,必須來自客戶端(瀏覽器),那麼,客戶端(瀏覽器)怎樣保存這個token?是保存在cookie還是storage?
- 請求的時候是cookie攜帶還是head攜帶?
Authorization: Bearer <token>
- 客戶端訪問另外一個服務器(跨域),怎樣攜帶這個token?
- 服務端token驗證,token, err := jwt.Parse(……token.Valid一句判斷,是否已經包含了token過期判斷了?答案是已經包含了過期檢測了。
搜了不少資料,開始都說要將token放在請求的head裏。
//請求中head中設置token
c.Ctx.Output.Header("TOKEN", tokenString)
c.Ctx.Output.Header("Authorization", tokenString)
//設置cookie 名稱,值,時間,路徑
c.Ctx.SetCookie("TOKEN", tokenString, "3600", "/")
比如,上面2個是放在response的Header,第三個放cookie中。
後來不少地方說放head不安全,放cookie雖然也會不安全,但可以預防……
跨域訪問網上都是在ajax等請求中放入token。JWT 也可放在 POST 請求的數據體裏面
liuxk: $.ajax({
type: 'GET',
url: url,
contentType: 'text/plain',
xhrFields: {
withCredentials: false
},
headers: {
"token": "xxxxx"
},
success: function(data) {
console.log(data)
},
error: function(error) {
console.log(error)
}
});
$.ajax({
url: host + "/order/autoImport",
method: 'post',
data: excel,
beforeSend: function(request) {
request.setRequestHeader("token", token);
request.setRequestHeader("version", version);
request.setRequestHeader("taskId", currentTask.id);
},
success: function(rs) {
}
})
golang beego:
// 校驗token是否有效 返回參數
func CheckToken(tokenString string) (userName string, err error) {
// tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
secret := beego.AppConfig.String("TokenSecrets")
// secret = "AllYourBase"
// userName := ""
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(secret), nil
})
if err != nil {
beego.Error(err)
return "", err
}
// token.Valid裏已經包含了過期判斷
if token != nil && token.Valid {
// fmt.Println("You look nice today")
claims, _ := token.Claims.(jwt.MapClaims)
userName = claims["userName"].(string)
}
// Token from another example. This token is expired
// token, err = jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// return []byte("secret"), nil
// })
// if token.Valid {
// fmt.Println("You look nice today")
// } else if ve, ok := err.(*jwt.ValidationError); ok {
// if ve.Errors&jwt.ValidationErrorMalformed != 0 {
// fmt.Println("That's not even a token")
// } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
// // Token is either expired or not active yet
// fmt.Println("Timing is everything")
// } else {
// fmt.Println("Couldn't handle this token:", err)
// }
// } else {
// fmt.Println("Couldn't handle this token:", err)
// }
return userName, err
}
//使用這個生成token
func CreateToken(userName string) (tokenString string, err error) {
token := jwt.New(jwt.SigningMethodHS256)
claims := make(jwt.MapClaims)
//添加令牌關鍵信息
Tokenexp, err := strconv.Atoi(beego.AppConfig.String("Tokenexp"))
if err != nil {
return tokenString, err
}
//添加令牌期限
claims["exp"] = time.Now().Add(time.Hour * time.Duration(Tokenexp)).Unix()
claims["iat"] = time.Now().Unix()
claims["userName"] = userName
token.Claims = claims
tokenString, err = token.SignedString([]byte(beego.AppConfig.String("TokenSecrets")))
if err != nil {
fmt.Println("generate json web token failed !! error :", err)
return tokenString, err
}
return tokenString, err
}