一、什么是appid、appkey、appsecret
AppID:应用的唯一标识
AppKey:公匙(相当于账号)
AppSecret:私匙(相当于密码)
app_id 是用来标记你的开发者账号的, 是你的用户id, 这个id 在数据库添加检索, 方便快速查找。
app_key 和 app_secret 是一对出现的账号, 同一个 app_id 可以对应多个 app_key+app_secret, 这样 平台就可以分配你不一样的权限, 比如 app_key1 + app_secect1 只有只读权限 但是 app_key2+app_secret2 有读写权限… 这样你就可以把对应的权限 放给不同的开发者. 其中权限的配置都是直接跟app_key 做关联的, app_key 也需要添加数据库检索, 方便快速查找。
至于为什么 要有app_key + app_secret 这种成对出现的机制呢, 因为 要加密, 通常 在首次验证(类似登录场景) , 你需要用 app_key(标记要申请的权限有哪些) + app_secret(密码, 表示你真的拥有这个权限) 来申请一个token, 就是我们经常用到的 access_token, 之后的数据请求, 就直接提供access_token 就可以验证权限了。
使用方法:
向第三方服务器请求授权时,带上AppKey和AppSecret(需存在服务器端)
第三方服务器验证AppKey和AppSecret在DB中有无记录
如果有,生成一串唯一的字符串(token令牌),返回给服务器,服务器再返回给客户端
客户端下次请求敏感数据时带上令牌
二、UUID
uuid是指在一台机器在同一时间中生成的数字在所有机器中都是唯一的,按照开放软件基金会(OSF)指定的标准计算,用到了以太网卡的地址、纳秒级时间、芯片ID码和愈多可能的数字。
UUID由以下几部分的组合:
1)当前日期和时间
2)时钟序列
3)全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),以连字号分为五段形式的36个字符
参考:UUID
2.0 golang三方库 "github.com/google/uuid" 中提供了生成uuid的方法
uuidByte, err := uuid.NewUUID()
uuid := uuidByte.String()
func NewUUID() (UUID, error) {
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
copy(uuid[10:], nodeID[:])
nodeMu.Unlock()
return uuid, nil
}
也可以自己生成uuid:
2.1 crypto/rand
var Reader io.Reader
Reader是一个全局、共享的密码用强随机数生成器。在Unix类型系统中,会从/dev/urandom读取;而Windows中会调用CryptGenRandom API。
import (
"crypto/rand"
"encoding/base64"
"io"
)
//sessionId函数用来生成一个session ID,即session的唯一标识符
func sessionId() string {
b := make([]byte, 32)
//ReadFull从rand.Reader精确地读取len(b)字节数据填充进b
//rand.Reader是一个全局、共享的密码用强随机数生成器
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return ""
}
fmt.Println(b) // [20 80 171 250 192 24 219 161 117 79 193 253 153 87 197 120 9 170 14 129 143 239 171 1 97 216 168 172 50 18 174 70]
return base64.URLEncoding.EncodeToString(b)//将生成的随机数b编码后返回字符串,该值则作为session ID
}
func main() {
fmt.Println(sessionId()) // FFCr-sAY26F1T8H9mVfFeAmqDoGP76sBYdiorDISrkY=
}
2.2 Rand UUID
package common
import (
crand "crypto/rand"
"encoding/hex"
"errors"
"fmt"
mrand "math/rand"
"regexp"
"strings"
"time"
)
// seeded indicates if math/rand has been seeded
var seeded bool = false
// uuidRegex matches the UUID string
var uuidRegex *regexp.Regexp = regexp.MustCompile(`^{?([a-fA-F0-9]{8})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{12})}?$`)
// UUID type.
type UUID [16]byte
// Hex returns a hex string representation of the UUID in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
func (this UUID) Hex() string {
x := [16]byte(this)
return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
x[0], x[1], x[2], x[3], x[4],
x[5], x[6],
x[7], x[8],
x[9], x[10], x[11], x[12], x[13], x[14], x[15])
}
// Rand generates a new version 4 UUID.
func Rand() UUID {
var x [16]byte
randBytes(x[:])
x[6] = (x[6] & 0x0F) | 0x40
x[8] = (x[8] & 0x3F) | 0x80
return x
}
// FromStr returns a UUID based on a string.
// The string could be in the following format:
//
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
//
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
//
// If the string is not in one of these formats, it'll return an error.
func FromStr(s string) (id UUID, err error) {
if s == "" {
err = errors.New("Empty string")
return
}
parts := uuidRegex.FindStringSubmatch(s)
if parts == nil {
err = errors.New("Invalid string format")
return
}
var array [16]byte
slice, _ := hex.DecodeString(strings.Join(parts[1:], ""))
copy(array[:], slice)
id = array
return
}
// randBytes uses crypto random to get random numbers. If fails then it uses math random.
func randBytes(x []byte) {
length := len(x)
n, err := crand.Read(x)
if n != length || err != nil {
if !seeded {
mrand.Seed(time.Now().UnixNano())
}
for length > 0 {
length--
x[length] = byte(mrand.Int31n(256))
}
}
}
func main() {
got := Rand().Hex()
fmt.Println(got) // 2df597df-b6ac-41d5-92e7-4e1aaba7f4c9
id, _ := FromStr(got)
fmt.Println(UUID(id)) // [45 245 151 223 182 172 65 213 146 231 78 26 171 167 244 201]
}
三、云服务 AppId或AppKey和AppSecret生成策略
import (
"crypto/sha1"
"encoding/hex"
"github.com/google/uuid"
"sort"
"strconv"
"strings"
//_uuid "myproject/uuid"
)
const (
SERVER_NAME = "myproject_abc123"
)
var (
chars = []string{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"}
)
func getAppKey() string {
// 1.
uuidByte, err := uuid.NewUUID()
if err != nil {
panic("new uuid error")
}
uuid := strings.ReplaceAll(uuidByte.String(), "-", "")
// 2.
//uuid := _uuid.Rand().Hex()
//uuid = strings.ReplaceAll(uuid, "-", "")
appKey := ""
for i := 0; i < 8; i++ {
str := uuid[i*4:i*4+4]
x, _ := strconv.ParseInt(str, 16, 64)
appKey += chars[x % 0x3e]
}
return appKey
}
func getAppSecret(appKey string) string {
sli := []string{appKey, SERVER_NAME}
sort.Strings(sli)
str := strings.Join(sli, "")
h := sha1.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
appKey := getAppKey()
appSecret := getAppSecret(appKey)
fmt.Println("appKey",appKey) // EO8bvxGl
fmt.Println("appSecret",appSecret) // 215bc9d7e1ab16c663289d40cea8164b9b00e307
}