我正在尝试使用 OpenIdConnect 客户端库在我的 Asp.Net Core 应用程序中实现 Sign In With Apple。在本文的帮助下https://www.scottbrady91.com/openid-connect/implementing-sign-in-with-apple-in-aspnet-core。当我在苹果控制台中创建应用程序时,一切正常https://developer.apple.com/account/resources/identifiers。但是,当我创建另一个应用程序(以及具有相应密钥的服务标识符)时,新应用程序无法工作。
如果我创建另一个应用程序/serviceId/密钥,它不会工作,直到我撤销第一个应用程序的密钥并为新应用程序创建新密钥。
如何创建两个可用的应用程序?有什么限制吗?
添加“apple”外部提供商:
.AddOpenIdConnect("apple", async options =>
{
options.ResponseType = "code id_token"; // hybrid flow due to lack of PKCE support
options.ResponseMode = "form_post"; // form post due to prevent PII in the URL
options.UsePkce = false; // apple does not currently support PKCE (April 2021)
options.DisableTelemetry = true;
options.Scope.Clear(); // apple does not support the profile scope
options.Scope.Add("openid");
options.Scope.Add("email");
options.Scope.Add("name");
options.Authority = "https://appleid.apple.com";
options.ClientId = configuration["Authentication:Apple:ClientId"]; // Service ID
options.CallbackPath = "/signin-apple";
options.Events.OnAuthorizationCodeReceived = context =>
{
context.TokenEndpointRequest.ClientSecret = AppleTokenGenerator.CreateNewToken(configuration["Authentication:Apple:Iss"],configuration["Authentication:Apple:ClientId"], configuration["Authentication:Apple:ClientSecret"]);
return Task.CompletedTask;
};
// TODO
})
public static string CreateNewToken(string iss, string sub, string privateKey)
{
const string aud = "https://appleid.apple.com";
var now = DateTime.UtcNow;
var ecdsa = ECDsa.Create();
ecdsa?.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);
var handler = new JsonWebTokenHandler();
return handler.CreateToken(new SecurityTokenDescriptor
{
Issuer = iss,
Audience = aud,
Claims = new Dictionary<string, object> { { "sub", sub } },
Expires = now.AddMinutes(60), // expiry can be a maximum of 6 months - generate one per request or re-use until expiration
IssuedAt = now,
NotBefore = now.AddMinutes(-60),
SigningCredentials = new SigningCredentials(new ECDsaSecurityKey(ecdsa), SecurityAlgorithms.EcdsaSha256)
});
}
授权请求工作正常。没有错误并将浏览器重定向到
options.CallbackPath = "/signin-apple";
令牌请求发生错误:
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'error_description is null', error_uri: 'error_uri is null'.
我模拟了请求:
curl --location --request POST 'https://appleid.apple.com/auth/token?grant_type=authorization_code&client_id=ua.secret.site&code=c3a55f910698647768b41e76a80881778.0.rwqy.Pt5lhGYR0eKHHmIOhsrkrw&redirect_uri=https://local.test:5001/signin-apple&client_secret=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1YS5zZWNyZXQuc2l0ZSIsImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJleHAiOjE2NTQwOTg2NjYsImlzcyI6IjdCNjREQzJYUE4iLCJpYXQiOjE2NTQwOTUwNjYsIm5iZiI6MTY1NDA5MTQ2Nn0.PkaPgnCF4u53w9yZgRXqmJ1xyN2DhTIukoknvRQ0jLfU4riVEUqPwh5c0Umx_cteadrcTjID-J_iH3hFPxUTrA'
并得到此回复:
{
"error": "invalid_client"
}
没有有用的响应标头
我还尝试了为两个不同的应用程序(t - 测试应用程序,p - 生产应用程序)释放和撤销密钥。 这是结果:
结论: 尽管是为不同的应用程序创建的,但两个键中一次只有一个可以工作。根据单个应用程序的密钥轮换规则,密钥将被无效(https://help.apple.com/developer-account/?lang=en#/dev77c875b7e),但有时不会。 我很困惑。
神奇的是添加这个
SigningCredentials = new SigningCredentials(new ECDsaSecurityKey(ecdsa){KeyId = keyId},
SecurityAlgorithms.EcdsaSha256)
当有一个密钥时它工作正常,但如果很少,我猜它需要最后一个密钥进行验证。 您需要添加 keyId 以便苹果识别密钥进行验证。