APP登录授权完成后,上传userID和identityToken给服务端,服务端进行JWT验证
服务端是用GO语言处理的,下面为GO语言的实现
package appleid
import (
"crypto/rsa"
"encoding/base64"
"encoding/json"
"errors"
"github.com/golang-jwt/jwt/v5"
"io/ioutil"
"math/big"
"net/http"
)
type AppleJwtKey struct {
Kty string `json:"kty"`
Kid string `json:"kid"`
Use string `json:"use"`
Alg string `json:"alg"`
N string `json:"n"`
E string `json:"e"`
}
type AppleJwtAuthKeys struct {
Keys []*AppleJwtKey `json:"keys"`
}
type AppleUser struct {
jwt.RegisteredClaims
}
func ParseJwtIdentityToken(identityToken, aud string) (*AppleUser, error) {
t, err := jwt.ParseWithClaims(identityToken, &AppleUser{}, func(token *jwt.Token) (interface{}, error) {
header := token.Header
kidStr := ""
if kid, ok := header["kid"]; ok {
kidStr = kid.(string)
} else {
return nil, errors.New("get kid failed")
}
//kidStr = "W6WcOKB"
return GetRSAPublicKey(kidStr), nil
}, jwt.WithAudience(aud))
if claims, ok := t.Claims.(*AppleUser); ok && t.Valid {
return claims, nil
} else {
return nil, err
}
}
func GetRSAPublicKey(kid string) *rsa.PublicKey {
resp, err := http.Get("https://appleid.apple.com/auth/keys")
if err != nil {
return nil
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil
}
var authKeys AppleJwtAuthKeys
err = json.Unmarshal(body, &authKeys)
if err != nil {
return nil
}
//fmt.Println(authKeys)
// 获取验证所需的公钥
var pubKey rsa.PublicKey
// 通过cliHeader的kid比对获取n和e值 构造公钥
for _, val := range authKeys.Keys {
if val.Kid == kid {
nByte, _ := base64.RawURLEncoding.DecodeString(val.N)
nData := new(big.Int).SetBytes(nByte)
eByte, _ := base64.RawURLEncoding.DecodeString(val.E)
eData := new(big.Int).SetBytes(eByte)
pubKey.N = nData
pubKey.E = int(eData.Uint64())
break
}
}
if pubKey.E <= 0 {
return nil
}
return &pubKey
}
文章评论