【问题标题】:404 error after Apple authentication using OpenId Connect使用 OpenId Connect 进行 Apple 身份验证后出现 404 错误
【发布时间】:2020-04-21 06:19:04
【问题描述】:

从 scottbrady91.com 采用,我正在尝试在我们的网站上进行 Apple 外部身份验证。我已经让微软的一台工作了,但苹果的一台还没有。用户已被定向到 appleid.apple.com,但经过身份验证后,它返回到 https://iluvrun.com/signin-apple(这是正确的),但未处理,因此用户收到 404 错误。

说实话,我不知道 signin-facebook、signin-google 或 signin-oidc 是如何工作的,但他们就是这样做的。所以我很难弄清楚为什么没有处理signin-apple。

该站点是使用 ASP.NET Web 窗体构建的。以下是我在 Startup.Auth.cs 的内容:

namespace ILR
{
    public partial class Startup {
        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login")
            });

            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions("Apple")
                {
                    ClientId = "com.iluvrun.login",
                    Authority = "https://appleid.apple.com/auth/authorize",
                    SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
                    RedirectUri = "https://iluvrun.com/signin-apple",
                    PostLogoutRedirectUri = "https://iluvrun.com",
                    Scope = "name email",
                    ResponseType = OpenIdConnectResponseType.Code,
                    ResponseMode = OpenIdConnectResponseMode.FormPost,
                    CallbackPath = PathString.FromUriComponent("/signin-apple"),
                    Configuration = new OpenIdConnectConfiguration
                    {
                        AuthorizationEndpoint = "https://appleid.apple.com/auth/authorize",
                        TokenEndpoint = "https://appleid.apple.com/auth/token"
                    },
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidIssuer = "https://appleid.apple.com",
                        IssuerSigningKey = new JsonWebKeySet(GetKeysAsync().Result).Keys[0]
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthorizationCodeReceived = (context) =>
                        {
                            context.TokenEndpointRequest.ClientSecret = TokenGenerator.CreateNewToken();

                            return Task.CompletedTask;
                        },
                        AuthenticationFailed = (context) =>
                        {
                            context.HandleResponse();
                            context.Response.Redirect("/Account/Login?errormessage=" + context.Exception.Message);

                            return Task.FromResult(0);
                        }
                    },
                    ProtocolValidator = new OpenIdConnectProtocolValidator
                    {
                        RequireNonce = false,
                        RequireStateValidation = false
                    }
                }
            );
        }

        private static async Task<string> GetKeysAsync()
        {
            string jwks = await new HttpClient().GetStringAsync("https://appleid.apple.com/auth/keys");

            return jwks;
        }
   }

    public static class TokenGenerator
    {
        public static string CreateNewToken()
        {
            const string iss = "CHM57Z5A6";
            const string aud = "https://appleid.apple.com";
            const string sub = "com.iluvrun.login";
            const string privateKey = "XXXX"; // contents of .p8 file
            CngKey cngKey = CngKey.Import(Convert.FromBase64String(privateKey), CngKeyBlobFormat.Pkcs8PrivateBlob);

            JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
            JwtSecurityToken token = handler.CreateJwtSecurityToken(
                issuer: iss,
                audience: aud,
                subject: new ClaimsIdentity(new List<Claim> { new Claim("sub", sub) }),
                expires: DateTime.UtcNow.AddMinutes(5),
                issuedAt: DateTime.UtcNow,
                notBefore: DateTime.UtcNow,
                signingCredentials: new SigningCredentials(new ECDsaSecurityKey(new ECDsaCng(cngKey)), SecurityAlgorithms.EcdsaSha256));

            return handler.WriteToken(token);
        }
    }
}

有没有人知道我想念什么才能让它工作?

【问题讨论】:

  • 你能做到吗?

标签: authentication authorization openid-connect


【解决方案1】:

您走在正确的轨道上,您的问题帮助我快速启动了我自己的解决方案,用于在我的项目中集成 Apple ID OpenIdConnect OWIN。在这里找到您的帖子后,我花了很长时间才解决所有问题。
使用您的代码后,我遇到了同样的 404 错误。

  1. 404 错误

这是由于 CreateNewToken() 方法中的未处理异常导致无法生成有效令牌。在我的情况下,它缺少我的 AppService 的 Azure 配置,在 CngKey.Import on azure 中有更多描述:

WEBSITE_LOAD_USER_PROFILE = 1

在 Azure 中设置此配置后,我转到下一个问题:

  1. 未调用令牌端点

这是由于 OpenIdConnectAuthenticationOptions 中缺少配置:

RedeemCode = true

此选项触发 OpenIdConnect 内部身份验证管道的所有下一步处理(TokenResponseReceived、SecurityTokenReceived、SecurityTokenValidated)

  1. AccountController.ExternalLoginCallback 令牌处理问题

这很棘手。因为你得到的只是在调用之后

var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();

得到:

loginInfo == null

因此,在阅读了很多关于此主题的问题文章(例如OWIN OpenID provider - GetExternalLoginInfo() returns null)并尝试之后,唯一的最终解决方法是将https://github.com/Sustainsys/owin-cookie-saver 添加到我的 Startup.cs 中,这解决了丢失令牌 cookie 的问题。它被标记为旧版,但这是我解决此问题的唯一选择。

所以我的工作解决方案的最终 OpenIdConnect 选项配置是:

            var appleIdOptions = new OpenIdConnectAuthenticationOptions
        {
            AuthenticationType = "https://appleid.apple.com",
            ClientId = "[APPLE_CLIENT_ID_HERE]",
            Authority = "https://appleid.apple.com/auth/authorize",
            SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
            RedirectUri = "https://www.europeanart.eu/signin-apple",
            PostLogoutRedirectUri = "https://www.europeanart.eu",
            Scope = OpenIdConnectScope.Email,
            RedeemCode = true,
            ResponseType = OpenIdConnectResponseType.CodeIdToken,
            ResponseMode = OpenIdConnectResponseMode.FormPost,
            CallbackPath = PathString.FromUriComponent("/signin-apple"),
            Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://appleid.apple.com/auth/authorize",
                TokenEndpoint = "https://appleid.apple.com/auth/token"
            },
            TokenValidationParameters = new TokenValidationParameters
            {
                ValidIssuer = "https://appleid.apple.com",
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                IssuerSigningKeys = new JsonWebKeySet(GetKeys()).Keys,
            },
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthorizationCodeReceived = (context) =>
                {
                    var clientToken = JwtTokenGenerator.CreateNewToken();

                    logger.LogInfo("Apple: clientToken generated");
                    context.TokenEndpointRequest.ClientSecret = clientToken;
                    logger.LogInfo("Apple: TokenEndpointRequest ready");

                    return Task.FromResult(0);
                },
                TokenResponseReceived = (context) =>
                {
                    logger.LogInfo("Apple: TokenResponseReceived");

                    return Task.FromResult(0);
                },
                SecurityTokenReceived = (context) =>
                {
                    logger.LogInfo("Apple: SecurityTokenReceived");

                    return Task.FromResult(0);
                },
                SecurityTokenValidated = (context) =>
                {
                    string userID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
                    logger.LogInfo("Apple: SecurityTokenValidated with userID=" + userID);

                    return Task.FromResult(0);
                },
                RedirectToIdentityProvider = (context) =>
                {
                    logger.LogInfo("Apple: RedirectToIdentityProvider");

                    if(context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
                    {
                        logger.LogInfo("Apple: RedirectToIdentityProvider -> Authenticate()");
                    }
                    else if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Token)
                    {
                        logger.LogInfo("Apple: RedirectToIdentityProvider -> Token()");
                    }

                    return Task.FromResult(0);
                },
                AuthenticationFailed = (context) =>
                {
                    context.HandleResponse();
                    logger.LogError("Apple Authentication Failed.", context.Exception);
                    context.Response.Redirect("/Account/Login?errormessage=" + context.Exception.Message);

                    return Task.FromResult(0);
                }
            },
            ProtocolValidator = new OpenIdConnectProtocolValidator
            {
                RequireNonce = false,
                RequireStateValidation = false
            }
        };

【讨论】:

    猜你喜欢
    • 2021-07-29
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 2019-12-16
    • 2016-06-28
    • 2016-11-27
    相关资源
    最近更新 更多