github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/auth/hmac.go (about)

     1  package auth
     2  
     3  import (
     4  	"crypto/hmac"
     5  	"crypto/sha256"
     6  	"encoding/base64"
     7  	"io"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  // HMACAuth HMAC算法鉴权
    14  type HMACAuth struct {
    15  	SecretKey []byte
    16  }
    17  
    18  // Sign 对给定Body生成expires后失效的签名,expires为过期时间戳,
    19  // 填写为0表示不限制有效期
    20  func (auth HMACAuth) Sign(body string, expires int64) string {
    21  	h := hmac.New(sha256.New, auth.SecretKey)
    22  	expireTimeStamp := strconv.FormatInt(expires, 10)
    23  	_, err := io.WriteString(h, body+":"+expireTimeStamp)
    24  	if err != nil {
    25  		return ""
    26  	}
    27  
    28  	return base64.URLEncoding.EncodeToString(h.Sum(nil)) + ":" + expireTimeStamp
    29  }
    30  
    31  // Check 对给定Body和Sign进行鉴权,包括对expires的检查
    32  func (auth HMACAuth) Check(body string, sign string) error {
    33  	signSlice := strings.Split(sign, ":")
    34  	// 如果未携带expires字段
    35  	if signSlice[len(signSlice)-1] == "" {
    36  		return ErrExpiresMissing
    37  	}
    38  
    39  	// 验证是否过期
    40  	expires, err := strconv.ParseInt(signSlice[len(signSlice)-1], 10, 64)
    41  	if err != nil {
    42  		return ErrAuthFailed.WithError(err)
    43  	}
    44  	// 如果签名过期
    45  	if expires < time.Now().Unix() && expires != 0 {
    46  		return ErrExpired
    47  	}
    48  
    49  	// 验证签名
    50  	if auth.Sign(body, expires) != sign {
    51  		return ErrAuthFailed
    52  	}
    53  	return nil
    54  }