前書き
ASP.NET Core で作成したウェブサイトに Sign in WIth Apple を組み込む必要があったので、調べたついでに導入手順を書き残します。
需要があるかわかりませんが、GitHub にサンプルもあげておきます。
https://github.com/Yuki0928/SignInWIthAppleSample
ASP .NET Core では Facebook、Twitter、Google、Microsoft などの外部プロバイダーの認証を非常に簡単にアプリに組み込めるのですが、Sign in with Apple は勝手が違うところがあり少し手間でした。
作業環境
Windows 10
Visual Studio 2019
Apple 開発者ポータルでの事前準備
アップルのヘルプなどを参考に Sign in with Apple を使用する準備を行います。
https://help.apple.com/developer-account/#/devde676e696
主な作業は3つです。
- App ID の作成
- Service ID の作成
- Private Key の作成
個人的にはヘルプは少々わかりづらかったので、こちらの記事を参考に準備を行いました。
https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple
ドメインと認証後のコールバック URL の登録 について
今回はローカルで動作確認を行うため、example.com と https://example.com:5001/signin-apple を登録し、hosts に 127.0.0.1 example.com のレコードを登録しました。
localhost で登録できればいいんですが、ちょっと面倒ですね。
ASP.NET Core Web アプリケーションを作成と動作確認
Visual Studio を起動して ASP.NET Core Web アプリケーション を作成します。
Web アプリケーション(モデル ビュー コントローラー)を選択します。
Properties から LaunchSettings.json を開きます。
下のほうの applicationUrl の localhost を example.com に書き換えます。
IIS Express の横の小さな三角ボタンを押して、SignInWithAppleSample を選択します。
SignInWithAppleSample ボタンを押します。
Windows ファイアウォールの警告が表示された場合はアクセスを許可します。
https://example.com:5001 で ASP.NET Core Web アプリケーションが動いていることが確認できました。このブラウザは一旦閉じます。
Microsoft.AspNetCore.Authentication.OpenIdConnect をインストール
NuGet で Microsoft.AspNetCore.Authentication.OpenIdConnect をインストールします。
TokenGenerator の作成
Model に TokenGenerator クラスを作成します。
TokenGenerator.cs のコードはこちらをコピペして上書きします。
iss、sub、kid、privateKey は自分の情報に書き換えます。(詳しくは後述)
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
namespace SignInWithAppleSample.Models
{
public static class TokenGenerator
{
public static string CreateNewToken()
{
const string iss = "TeamID をいれます";
const string sub = "ServiceID をいれます";
const string kid = "KeyID をいれます";
const string privateKey = "PrivateKey をいれます";
var cngKey = CngKey.Import(
Convert.FromBase64String(privateKey),
CngKeyBlobFormat.Pkcs8PrivateBlob);
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateJwtSecurityToken(
issuer: iss,
audience: "https://appleid.apple.com",
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)) { KeyId = kid }, SecurityAlgorithms.EcdsaSha256));
return handler.WriteToken(token);
}
}
}
TeamID と ServiceID は Apple の開発者ポータルから取得します。
KeyID とPrivateKey は開発者ポータルで Key を発行したときに AuthKey_xxxxxxxxxx.p8
というファイルをダウンロードしているはずですのでそちらから取得します。
KeyID は上記のファイル名の xxxxxxxxxx の部分です。
PrybateKey はファイル内の文字列の改行を削除して1行にしたものを入れます。
先頭の -----BEGIN PRIVATE KEY-----
と末尾の -----END PRIVATE KEY-----
も削除してください。
Sign in with Apple を組み込む
using を追加します。
using System.Net.Http;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using SignInWithAppleSample.Models;
ConfigureServices メソッド を以下のように書き換えます。
ServiceID は先ほどと同じものをいれます。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(async options =>
{
options.ClientId = "ServiceID をいれます";
options.CallbackPath = "/signin-apple";
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Clear();
options.Configuration = new OpenIdConnectConfiguration
{
AuthorizationEndpoint = "https://appleid.apple.com/auth/authorize",
TokenEndpoint = "https://appleid.apple.com/auth/token",
};
options.Events.OnAuthorizationCodeReceived = context =>
{
context.TokenEndpointRequest.ClientSecret = TokenGenerator.CreateNewToken();
return Task.CompletedTask;
};
options.TokenValidationParameters.ValidIssuer = "https://appleid.apple.com";
var jwks = await new HttpClient().GetStringAsync("https://appleid.apple.com/auth/keys");
options.TokenValidationParameters.IssuerSigningKeys = new JsonWebKeySet(jwks).Keys;
options.ProtocolValidator.RequireNonce = false;
});
}
Configure メソッドに app.UseAuthentication();
を追加します。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication(); // この1行を追加
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
適当な場所に SignInWithApple メソッドを追加します。
public IActionResult SignInWithApple ()
{
return Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectDefaults.AuthenticationScheme);
}
末尾に以下のコードを書き足します。
@if (User.Identity.IsAuthenticated)
{
@User.Claims.First(x => x.Type.Contains("nameidentifier")).Value
}
else
{
@Html.ActionLink("Sign in With Apple でサインインする", "SignInWithApple")
}
以上で導入は一旦完了です。
ログアウト処理を書いていませんが、Sign in with Apple だからといって変わったことはないのでここでは割愛します。
Sign in With Apple の動作確認
最初の動作確認と同様に Web アプリケーションをデバッグ実行します。
Sign in With Apple でサインインする のリンクをクリックします。
サインインすると元の画面に戻ります。
Apple から取得したユーザーの ID が表示されます。
これでアプリやゲームに Sign in With Apple を組み込めますね!