Files
xiaomihome/xiaomi/oauth.go
T
4566704 8ffc9e4e44 refactor: 重构 token 管理,新增 NATS adapter 和多示例
按照 TOKEN_REFACTOR.md / FIX_CONFIG.md 方案重构核心层:
- miot: Init() 优先读 storage token,新增 RefreshAuthInfo() 和刷新回调
- xiaomi: Config 改用 AuthInfo 结构体(含 UUID/UID/DataDir/OnTokenRefreshed)
- xiaomi: NewClient(ctx, Config) 新签名,新增 RefreshToken(),后台自动刷新
- xiaomi/devices: 设备控制接口重构
- 新增示例 12_ac_subscribe,其余示例适配新 Config
2026-06-30 12:16:49 +08:00

60 lines
1.5 KiB
Go

package xiaomi
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"time"
"xiaomihome/miot"
)
// TokenResult OAuth token 交换/刷新结果
type TokenResult struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
ExpiresTS int64 `json:"expires_ts"`
UID string `json:"uid"`
}
// AuthURL 生成小米 OAuth 授权页面 URL。
func AuthURL(cfg Config) string {
oa := miot.NewMIoTOauthClient(miot.OAUTH2_CLIENT_ID, "", "cn", generateUUID())
return oa.GenAuthURL("", "", nil, false)
}
// ExchangeCode 用 authorization code 交换 access token。
func ExchangeCode(ctx context.Context, cfg Config, code string) (*TokenResult, error) {
oa := miot.NewMIoTOauthClient(miot.OAUTH2_CLIENT_ID, "", "cn", generateUUID())
result, err := oa.GetAccessToken(code)
if err != nil {
return nil, fmt.Errorf("xiaomi: exchange token: %w", err)
}
expiresIn := intVal(result, "expires_in")
return &TokenResult{
AccessToken: strVal(result, "access_token"),
RefreshToken: strVal(result, "refresh_token"),
ExpiresIn: expiresIn,
ExpiresTS: time.Now().Unix() + int64(expiresIn),
UID: strVal(result, "uid"),
}, nil
}
func generateUUID() string {
b := make([]byte, 16)
rand.Read(b)
buf := make([]byte, 36)
hex.Encode(buf[:8], b[:4])
buf[8] = '-'
hex.Encode(buf[9:13], b[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], b[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], b[8:10])
buf[23] = '-'
hex.Encode(buf[24:], b[10:16])
return string(buf)
}