# 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;
}
}
```