# Net Core 使用apple登入(openId 套件) ###### tags: `apple` `.net core` `openId` `第三方登入` ## 方法2:使用套件(openid) [範例原文](https://www.scottbrady91.com/openid-connect/implementing-sign-in-with-apple-in-aspnet-core) #### Apple 開發者帳戶設定 [官方設定說明](https://help.apple.com/developer-account/#/dev1c0e25352) 創建為“使用 Apple 登錄”配置的 App ID 創建為“使用 Apple 登錄”配置的服務 ID(包括經過驗證的網域和redirect URIs) 創建一個可由您創建的服務 ID 使用的密鑰(p8) 不幸的是,redirect URIs不能使用 localhost ,但是可以在本機上修改測試用網域` http://dino.com/signin-apple` (在C:\Windows\System32\drivers\etc\hosts 中可以加入設定使 127.0.0.1 可以對應到 dino.com) `127.0.0.1 dino.com` 修改專案的開啟網址(localhost:5000 → dino.com(443 port)) `.\Properties\launchSettings.json` ``` "projectname": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" }, "dotnetRunMessages": "true", "applicationUrl": "https://dino:443;http://localhost:5000" } ``` #### Startup ``` services.AddAuthentication(options => { options.DefaultScheme = "cookie"; options.DefaultChallengeScheme = "apple"; }).AddCookie("cookie").AddOpenIdConnect("apple", options => { options.Authority = "https://appleid.apple.com"; // disco doc: https://appleid.apple.com/.well-known/openid-configuration options.ClientId = ""; // Service ID options.CallbackPath = "/signin-apple"; // corresponding to your redirect URI 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.DisableTelemetry = true; options.Scope.Clear(); // apple does not support the profile scope options.Scope.Add("openid"); options.Scope.Add("email"); options.Scope.Add("name"); // custom client secret generation - secret can be re-used for up to 6 months options.Events.OnAuthorizationCodeReceived = context => { context.TokenEndpointRequest.ClientSecret = TokenGenerator.CreateNewToken(); return Task.CompletedTask; }; options.UsePkce = false; }); ``` #### Controller 這邊需要注意當有多個第三方登入同時存在時AuthenticateAsync需要指定明確OpenIdConnect的名稱,否則會出現錯誤。 EX: HttpContext.AuthenticateAsync("apple") ``` [AllowAnonymous] [HttpGet] public async Task<IActionResult> TestChallenge() { var result = await HttpContext.AuthenticateAsync("apple"); var cccc = HttpContext.User.Claims; if (result.Succeeded) { return RedirectToAction("Index"); } return Challenge("apple"); } ``` #### View 只要可以連到對應controller的Action即可,方法不限制只能使用`<a>` 也可以傳入參數進行登入後的判斷。 ``` <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="TestChallenge">Sign In with Apple</a> ``` #### Helper ``` public static class TokenGenerator { public static string CreateNewToken() { const string iss = "6YPRZBQSZE"; // your account's team ID found in the dev portal const string aud = "https://appleid.apple.com"; const string sub = "com.icirround.ContactBook.AppleSignIn"; // same as client_id var now = DateTime.UtcNow; // contents of your .p8 file const string privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQghg+OSFvegWxnlR1G0DPK9L9yyjf6xYg/ek15jRN0OFugCgYIKoZIzj0DAQehRANCAAQW40tJJig10T4SaGDB3ePNH3ymGV4VCf2fuO/qDMVn83XTi9kfXbP6DKREP8D8pBudopETjPeALI5/zh0sT7sM"; var ecdsa = ECDsa.Create(); ecdsa?.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _); var handler = new JsonWebTokenHandler(); var result = handler.CreateToken(new SecurityTokenDescriptor { Issuer = iss, Audience = aud, Claims = new Dictionary<string, object> { { "sub", sub } }, Expires = now.AddMonths(1), // expiry can be a maximum of 6 months - generate one per request or re-use until expiration IssuedAt = now, NotBefore = now, SigningCredentials = new SigningCredentials(new ECDsaSecurityKey(ecdsa), SecurityAlgorithms.EcdsaSha256) }); return result; } } ```