package auth import ( "bytes" "crypto/hmac" "crypto/sha1" "encoding/base32" "encoding/binary" "fmt" "net/url" "strings" "time" ) type GoogleAuth struct { } func NewGoogleAuth() *GoogleAuth { return &GoogleAuth{} } func (googleAuth *GoogleAuth) un() int64 { return time.Now().UnixNano() / 1000 / 30 } func (googleauth *GoogleAuth) hmacSha1(key, data []byte) []byte { h := hmac.New(sha1.New, key) if total := len(data); total > 0 { h.Write(data) } return h.Sum(nil) } func (googleauth *GoogleAuth) base32encode(src []byte) string { return base32.StdEncoding.EncodeToString(src) } func (googleauth *GoogleAuth) base32decode(s string) ([]byte, error) { return base32.StdEncoding.DecodeString(s) } func (googleauth *GoogleAuth) toBytes(value int64) []byte { var result []byte mask := int64(0xFF) shifts := [8]uint16{56, 48, 40, 32, 24, 16, 8, 0} for _, shift := range shifts { result = append(result, byte((value>>shift)&mask)) } return result } func (googleauth *GoogleAuth) toUint32(bts []byte) uint32 { return (uint32(bts[0]) << 24) + (uint32(bts[1]) << 16) + (uint32(bts[2]) << 8) + uint32(bts[3]) } func (googleauth *GoogleAuth) oneTimePassword(key []byte, data []byte) uint32 { hash := googleauth.hmacSha1(key, data) offset := hash[len(hash)-1] & 0x0F hashParts := hash[offset : offset+4] hashParts[0] = hashParts[0] & 0x7F number := googleauth.toUint32(hashParts) return number % 1000000 } // 获取秘钥 func (googleauth *GoogleAuth) GetSecret() string { var buf bytes.Buffer binary.Write(&buf, binary.BigEndian, googleauth.un()) return strings.ToUpper(googleauth.base32encode(googleauth.hmacSha1(buf.Bytes(), nil))) } func (googleauth *GoogleAuth) GetSecretByStr(str string) string { var buf bytes.Buffer binary.Write(&buf, binary.BigEndian, googleauth.un()) return strings.ToUpper(googleauth.base32encode([]byte(str))) } // 获取动态码 func (googleauth *GoogleAuth) GetCode(secret string) (string, error) { secretUpper := strings.ToUpper(secret) secretKey, err := googleauth.base32decode(secretUpper) if err != nil { return "", err } number := googleauth.oneTimePassword(secretKey, googleauth.toBytes(time.Now().Unix()/30)) return fmt.Sprintf("%06d", number), nil } // 获取动态码二维码内容 func (googleauth *GoogleAuth) GetQrcode(user, secret string) string { return fmt.Sprintf("otpauth://totp/%s?secret=%s", user, secret) } // 获取动态码二维码图片地址,这里是第三方二维码api func (googleauth *GoogleAuth) GetQrcodeUrl(user, secret string) string { qrcode := googleauth.GetQrcode(user, secret) width := "200" height := "200" data := url.Values{} data.Set("data", qrcode) return "https://api.qrserver.com/v1/create-qr-code/?" + data.Encode() + "&size=" + width + "x" + height + "&ecc=M" } // 验证动态码 func (googleauth *GoogleAuth) VerifyCode(secret, code string) (bool, error) { _code, err := googleauth.GetCode(secret) fmt.Println(_code, code, err) if err != nil { return false, err } return _code == code, nil }