76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
package searchaccessser
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common/crypt"
|
|
)
|
|
|
|
const (
|
|
tokenScope = "video_search_access"
|
|
tokenTTL = 10 * time.Minute
|
|
)
|
|
|
|
// Issue 为搜索结果签发短时效的视频访问凭证。
|
|
func Issue(uid uint64, videoID string, now time.Time) (string, error) {
|
|
return issue(appg.Conf.Base.JwtKey, uid, videoID, now)
|
|
}
|
|
|
|
// Validate 校验搜索结果访问凭证,凭证与用户和视频一一绑定。
|
|
func Validate(token string, uid uint64, videoID string, now time.Time) bool {
|
|
return validate(appg.Conf.Base.JwtKey, token, uid, videoID, now)
|
|
}
|
|
|
|
func issue(secret string, uid uint64, videoID string, now time.Time) (string, error) {
|
|
if videoID == "" {
|
|
return "", errors.New("video id is empty")
|
|
}
|
|
return crypt.CreateToken(searchTokenSecret(secret), map[string]interface{}{
|
|
"scope": tokenScope,
|
|
"uid": uid,
|
|
"vid": videoID,
|
|
"iat": now.Unix(),
|
|
"exp": now.Add(tokenTTL).Unix(),
|
|
})
|
|
}
|
|
|
|
func validate(secret, token string, uid uint64, videoID string, now time.Time) bool {
|
|
claims, err := crypt.ParseToken(searchTokenSecret(secret), token)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
scope, _ := claims["scope"].(string)
|
|
vid, _ := claims["vid"].(string)
|
|
tokenUID, uidOK := numberClaim(claims["uid"])
|
|
expiresAt, expOK := numberClaim(claims["exp"])
|
|
return scope == tokenScope &&
|
|
vid == videoID &&
|
|
uidOK &&
|
|
tokenUID == int64(uid) &&
|
|
expOK &&
|
|
expiresAt >= now.Unix()
|
|
}
|
|
|
|
func searchTokenSecret(secret string) string {
|
|
if secret == "" {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("%s:%s", secret, tokenScope)
|
|
}
|
|
|
|
func numberClaim(value interface{}) (int64, bool) {
|
|
switch number := value.(type) {
|
|
case float64:
|
|
return int64(number), true
|
|
case int64:
|
|
return number, true
|
|
case int:
|
|
return int64(number), true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|