.net - 在 .net 后端使用苹果 JS 登录验证 AuthToken
问题描述
我正在尝试在我们的 Web 应用程序上实现 Sign in with apple,它适用于 AppleTV 和 IOS,但相同的流程似乎不适用于来自 Apple JS 的令牌,我得到INVALID_CLIENT
.
似乎它需要一些额外的步骤,所以我添加了 KID 等,现在我被困住了INVALID_GRANT
(根据我的理解,这更好,至少客户还可以)。
从Js
侧面看,我做了以下事情:(流程似乎是正确的,有适当的回应AppleIDSignInOnSuccess
)
AppleID.auth.init({
clientId: 'com.#########.weblogin',//service Id created
scope: 'name email',
state: state,
redirectURI: location.href,
usePopup: true //or false defaults to false
});
document.addEventListener('AppleIDSignInOnSuccess', (data) => {
//handle successful response
var deviceKey = document.cookie.replace(/(?:(?:^|.*;\s*)deviceKey\s*\=\s*([^;]*).*$)|^.*$/, "$1");
requestLogin({
AppleToken: data.detail.authorization.id_token,
AppleAuthorizationCode: btoa(data.detail.authorization.code),//our api requires base64urlsafe strings to be symetric with native apps
FirstName: data.detail.user?.firstName,
LastName: data.detail.user?.LastName,
DeviceKey: deviceKey
});
});
需要注意的是,虽然与文档 [state] 不同,不会返回,但在弹出的情况下可能没有必要,但这可能表明出现问题。
现在我用我的.NET
后端处理 AuthorizationCode。
Hclient.DefaultRequestHeaders.Add("User-Agent", "Microsoft ASP.NET Core OpenIdConnect handler");
var datas = new Dictionary<string, string="">()
{
{ "client_id" , request.DeviceKey.StartsWith("WEB_") ? "com.########.weblogin" : "com.########.app" }, //use the serviceId and not the main appId for web
{ "code" , request.AppleAuthorizationCode.FromBase64UrlSafe().FromUtf8Bytes() },
{ "grant_type" , "authorization_code" },
{ "redirect_uri", "https://login.#######.com/signin-apple" },
{"client_secret",request.DeviceKey.StartsWith("WEB_") ? TokenGenerator2.CreateNewToken() : TokenGenerator.CreateNewToken() }//generate the client_secret differently for web
};
var formdata = new FormUrlEncodedContent(datas);
using (HttpResponseMessage res = Hclient.PostAsync("https://appleid.apple.com/auth/token",formdata ).Result)
这是响应“INVALID_GRANT”的调用。这就是我生成 jwt 令牌 client_secret 的方式。
public static class TokenGenerator2
{
public static string CreateNewToken()
{
const string iss = "7#######G"; // team ID
const string aud = "https://appleid.apple.com";
const string sub = "com.#######.weblogin"; // service Id
const string keyId = "G######W";//key Idassociated with the p8 file
const string privateKey = "MIGT####...#####"; // contents of AuthKey_[keyId].p8 file
var d = DateTime.UtcNow.AddDays(-5);//I was worried the date time was the issue so I took a laaaaarge one ...
var cngKey = CngKey.Import(
Convert.FromBase64String(privateKey),
CngKeyBlobFormat.Pkcs8PrivateBlob);
var handler = new JwtSecurityTokenHandler();
var securityKey = new ECDsaSecurityKey(new ECDsaCng(cngKey) { KeySize = 256 , HashAlgorithm = CngAlgorithm.ECDsaP256});
securityKey.KeyId = keyId;
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.EcdsaSha256);
return handler.CreateEncodedJwt(iss, aud, new ClaimsIdentity(new List { new Claim("sub", sub) }),d, expires: d.AddMonths(3),d, signingCredentials: signingCredentials);
}
}
作为参考,这是我为本机应用程序创建它的方式(有效的流程)
public static class TokenGenerator
{
public static string CreateNewToken()
{
const string iss = "7#######G"; // your account's team ID found in the dev portal
const string aud = "https://appleid.apple.com";
const string sub = "com.######.app";
const string privateKey = "MIGTAg###...####"; // contents of .p8 file
var cngKey = CngKey.Import(
Convert.FromBase64String(privateKey),
CngKeyBlobFormat.Pkcs8PrivateBlob);
var d = DateTime.UtcNow.AddDays(-5);
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateJwtSecurityToken(
issuer: iss,
audience: aud,
subject: new ClaimsIdentity(new List { new Claim("sub", sub) }),
expires: d.AddMonths(3), // expiry can be a maximum of 6 months
issuedAt: d,
notBefore: d,
signingCredentials: new SigningCredentials(
new ECDsaSecurityKey(new ECDsaCng(cngKey)), SecurityAlgorithms.EcdsaSha256));
return handler.WriteToken(token);
}
}