first commit

This commit is contained in:
Yangtao
2025-11-18 17:48:20 +08:00
commit 6e56cab848
196 changed files with 65809 additions and 0 deletions

View File

@ -0,0 +1,166 @@
package Apple
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"net/http"
"servicebase/pkg/common/HyTools"
"time"
"github.com/anxpp/beego/logs"
"github.com/dgrijalva/jwt-go"
"github.com/spf13/viper"
)
const (
AppleServerApiUrl = "https://appleid.apple.com/auth/token"
)
// 苹果登录
type AppleClient struct {
}
func NewAppleClient() *AppleClient {
return &AppleClient{}
}
type Claims struct {
jwt.StandardClaims
Iss string `json:"iss"`
Aud string `json:"aud"`
Exp int64 `json:"exp"`
Iat int64 `json:"iat"`
Sub string `json:"sub"`
AtHash string `json:"at_hash"`
Email string `json:"email"`
EmailVerified string `json:"email_verified"`
AuthTime int64 `json:"auth_time"`
NonceSupported bool `json:"nonce_supported"`
}
type ResJwt struct {
Token string `json:"access_token"`
Type string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
IdToken string `json:"id_token"`
}
// 验证code
func (client *AppleClient) VerifyAppleAuthCode(authCode string) (appleUserId string, resultErr error) {
apiUrl := AppleServerApiUrl
clientId := viper.GetString("apple.IOSBundleId")
param := make(map[string]string, 0)
param["client_id"] = clientId
param["code"] = authCode
param["grant_type"] = viper.GetString("apple.GrantType")
// 生成密钥
secret := client.GenerateClientSecret()
if len(secret) == 0 {
resultErr = errors.New("生成密钥出错")
return
}
param["client_secret"] = secret
paramString := ""
for k, v := range param {
kv := k + "=" + v + "&"
paramString += kv
}
if len(paramString) > 0 {
paramString = HyTools.Substr(paramString, 0, len(paramString)-1)
}
logs.Info("signWithApple params:" + paramString)
headerMap := make(map[string]string, 0)
headerMap["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8"
result, err := HyTools.HttpDo(http.MethodPost, apiUrl, headerMap, paramString)
if err != nil {
logs.Error("苹果登录失败,请求API失败:" + err.Error())
resultErr = err
return
}
logs.Info("signWithApple result:" + result)
var resultDTO ResJwt
e := json.Unmarshal([]byte(result), &resultDTO)
if e != nil {
logs.Error("苹果登录失败,JSON:" + e.Error())
resultErr = err
return
}
token, _ := jwt.ParseWithClaims(resultDTO.IdToken, &Claims{}, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v ", token.Header["alg"])
}
return token, nil
})
if claims, ok := token.Claims.(*Claims); ok {
appleUserId = claims.Sub
} else {
resultErr = errors.New("jwt error, token not correct")
}
return
}
// 生成jwt密钥
func (client *AppleClient) GenerateClientSecret() (secret string) {
token := &jwt.Token{
Header: map[string]interface{}{
"alg": "ES256",
"kid": viper.GetString("apple.KeyId"),
},
Claims: jwt.MapClaims{
"iss": viper.GetString("apple.TeamId"),
"iat": time.Now().Unix(),
// constraint: exp - iat <= 180 days
"exp": time.Now().Add(24 * time.Hour).Unix(),
"aud": "https://appleid.apple.com",
"sub": viper.GetString("apple.IOSBundleId"),
},
Method: jwt.SigningMethodES256,
}
ecdsaKey, _ := AuthKeyFromBytes([]byte(viper.GetString("apple.PrivateKey")))
ss, _ := token.SignedString(ecdsaKey)
secret = ss
return
}
func AuthKeyFromBytes(key []byte) (*ecdsa.PrivateKey, error) {
var err error
// Parse PEM block
var block *pem.Block
if block, _ = pem.Decode(key); block == nil {
return nil, errors.New("token: AuthKey must be a valid .p8 PEM file")
}
// Parse the key
var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err
}
var pkey *ecdsa.PrivateKey
var ok bool
if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
return nil, errors.New("token: AuthKey must be of type ecdsa.PrivateKey")
}
return pkey, nil
}

View File

@ -0,0 +1,32 @@
package Apple
import (
"encoding/json"
"fmt"
"github.com/anxpp/beego/logs"
"github.com/dgrijalva/jwt-go"
"testing"
)
func TestAppleClient_VerifyAppleAuthCode(t *testing.T) {
result := `{"access_token":"a43aca909b09c47e7ab17cf65f2f87d5a.0.mrwxs.NGHQpX4Dp1mHUeGiC7UF7A","token_type":"Bearer","expires_in":3600,"refresh_token":"r472107c8150844c0995604692008d3c5.0.mrwxs.WE3wQnwhQpVVX77-U6169A","id_token":"eyJraWQiOiI4NkQ4OEtmIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY24ubWVldGFsay5lbmVuIiwiZXhwIjoxNTk4MTA1NDE2LCJpYXQiOjE1OTgxMDQ4MTYsInN1YiI6IjAwMTY3Mi43NTQyNGFiMGRjYWM0YTM2YTkxMmI5NDNmMzg5MmQ4ZC4xMDUzIiwiYXRfaGFzaCI6IlUwVUM5QTdnRWc4cnFfOHVORWxocVEiLCJlbWFpbCI6IjgzNDA3NzA2NUBxcS5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJhdXRoX3RpbWUiOjE1OTgxMDQ4MTMsIm5vbmNlX3N1cHBvcnRlZCI6dHJ1ZX0.G1GwHu5qWW1Hj8-E2BObM3BIwi0ntDeoX0ymHR2EufgXxWcBI7rePadO2vGqJIRFpzsoN7ixRT1-ChpvUT7X37izDqCMHRTsBgEEKqh15gvgB-siYfssBmojcJx4W_DcKx24-4Z_mi4_BejPU6_kstJrlOPzh33dOPiUZJcY0pAWpynaTPFR3WkdbLd7RB9N-s5Z9jY2VF2SQLA8kkTcdRZQsfagErGcawJK6zttkR8EwK3D0wo_cfXoJ9Q49fayzAwkyhqfMrAWZZVwzDDtdNq4dmXfnPxNG1pootRF4PZE1IkJKteN0262xp4XZEBuWsMBeUwwjHlpu4gr77Re9w"}`
var resultDTO ResJwt
e := json.Unmarshal([]byte(result), &resultDTO)
if e != nil {
logs.Error("JSON:" + e.Error())
return
}
secret := NewAppleClient().GenerateClientSecret()
token, jwtError := jwt.ParseWithClaims(resultDTO.IdToken, &Claims{}, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v ", token.Header["alg"])
}
return []byte(secret), nil
})
logs.Info(jwtError)
logs.Info(token.Valid)
logs.Info(token.SigningString())
logs.Info(token.Claims.(*Claims).Sub)
}