注意!本書は ASP.NET Core プラットフォームのバージョン 2.0 を参照しています。ASP.NET Core 1.0 をセキュアにする方法をお探しの方は、 ASP.NET Core 認証チュートリアル セクションをご参照ください。お楽しみください!
TL;DR: 以前のバージョンとは異なり、ASP.NET Core 2 は JSON Web Token に対するネイティブサポートを提供します。このサポートにより、ASP.NET アプリケーションにおけるこのテクノロジをより簡単な方法で統合することができます。本書では、ASP.NET Core 2 をベースにして Web API アプリケーションを作成する際 JWT を有効にする方法を見ていきます。 最終コードはこの GitHub レポジトリで検索できます。
JWT への簡単な概要
JSON Web Token(短縮して JWT)は Web 環境においてますます人気を集めています。 JWT は、コンパクトかつセキュアな方法で JSON オブジェクトとしてパーティ間でデータ送信を可能にするオープンスタンダードです。ソースおよびターゲット間で送信されるデータは簡単に検証を受け、信頼が得られるようにデジタル署名されているので、通常、認証や情報交換を行う際に使用されています。
JWT は以下の 3 つのセクションで構成されています。
: これは JWT のタイプや、データを暗号化するために使用するハッシュ アルゴリズムについてのメタ情報を含む JSON オブジェクトです。Header
: ソースおよびターゲット間で実際に共有されるデータを含む JSON オブジェクトであっても、これらのデータは claims でコード化され、エンティティについて、一般的にはユーザーについてのステートメントです。Payload
: このセクションは上記の 2 つのセクションをベースにしたデジタル署名を表すので、データの整合性を確認することができます。Signature
JWT の 3 つのセクションは、データが HTTP ベース環境に簡単に送信できるようにドット(.)で区切った Base64 文字列 のシーケンスに統合されています。認証で使用するときは、JWT テクノロジーはクライアントにセッションデータを保存できるようにし、保護されたリソースにアクセスしようとする際にはトークンをサーバーに提供します。通常、トークンは Bearer スキーマ を使って
Authorization
HTTP ヘッダーでにあるサーバーに送信され、それにはそのリソースへのアクセス許可または拒否を可能にするすべての情報が含まれています。もちろん、本書は一般用語やテクノロジーの基本的なアイディアを含む JWTについての簡単な概要です。詳細については、 JSON Web Token の概要をご覧ください。
“JSON Web Token は JSON オブジェクトとしてパーティ間で安全に情報を送信するためのコンパクトで自己完結型のTokenです。”
これをツイートする
ASP.NET Core 2.0 アプリケーションを JWT でセキュアする
Web API アプリケーションを作成しながら、JWT をサポートした ASP.NET Core 2 アプリケーション をセットアップする方法を見てみましょう。Visual Studio を使って、またはコマンドラインを通してこのアプリケーションを作ることができます。前者の場合では、次の画像で示すようにASP.NET Core Web アプリケーション プロジェクトテンプレートを選択します。
次に、ASP.NET アプリケーションのタイプを選択しますが、この場合では、次の画像で示すようにWeb APIを選択します。
簡便性のため、JWTの管理にフォーカスしたいので、ここでは認証のどのタイプの認証にも可能にしていません。
コマンドラインからアプリケーションを作りたい場合は、以下のコマンドを通して作成することができます。
dotnet new webapi -n JWT
これで、現在のフォルダに JWT という名前の ASP.NET Web API プロジェクトを作られます。
プロジェクトの作成方法にかかわらず、基本的な ASP.NET Core 2 Web API アプリケーションを設定するクラスを定義するファイルがフォルダに作成されます。
まず最初に、JWT ベース認証のサポートを構成するために、
Startup.cs
の ConfigureServices
メソッドの本文を変更します。以下は、ConfigureServices
の実装によるものです。using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; namespace JWT { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // このメソッドはランタイムで呼び出されます。このメソッドを使って HTTP リクエストパイプラインを構成します。 public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = Configuration["Jwt:Issuer"], ValidAudience = Configuration["Jwt:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) }; }); services.AddMvc(); } } }
ここで、
AddAuthentication
メソッドを使って JwtBearerDefaults.AuthenticationScheme
を指定して JWT 認証スキーマを登録します。次に JWT Bearerオプションで認証を構成します。特に、 JSON Web Token の有効性を検討するために、どのパラメーターを考慮しなければならないかを指定します。このコードでは、トークンの有効性を検討するには以下をしなければならないとしています。- トークンを作成したサーバーを検証する(
)ValidateIssuer = true
- トークンの受信人が受信を許可されているかを確認する (
)ValidateAudience = true
- トークンの期限が切れておらず、Issuerの署名鍵が有効であることをチェックする (
)ValidateLifetime = true
- 受信したトークンを署名するために使用された鍵が信頼された鍵のリストに入っていることを検証する (
)。ValidateIssuerSigningKey = true
また、Issuer、audience、および署名鍵の値も指定します。これらの値は
appsettings.json
ファイルに保存し、以下のConfiguration
オブジェクトを通してアクセスできるようにします。//appsettings.json { // ... "Jwt": { "Key": "veryVerySecretKey", "Issuer": "http://localhost:63939/" } }
このステップでは JWT ベースの認証サービスを構成します。この認証サービスがアプリケーションで使用できるようにするため、
app.UseAuthentication()
を呼び出す Configure
メソッドを Startup
クラスに作成します。// その他のメソッド
// その他のメソッド public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAuthentication(); app.UseMvc(); }
この変更で、JWT ベースの認証をサポートするアプリケーションの構成が完了します。
ASP.NET Core 1.0 と ASP.NET Core 2.0 の比較
どのように ASP.NET Core 1.x が JWT をサポートするかについてご存知であれば、その有効性をすでに経験されていることでしょう。
まずはじめに、ASP.NET Core の以前のバージョンでは、外部パッケージをいくつかインストールする必要がありました。2.0ではJSON Web Token はネイティブでサポートされているので、これらをインストールする必要がなくなりました。
また、総合的な認証システムの結果として、構成手順が簡潔化されました。実際、ASP.NET Core 1.0 ではサポートする各認証スキーマごとにそれぞれ1 つのミドルウェアがありましたが、ASP.NET Core 2.0 では 1 つのミドルウェアが全ての認証を処理し、各認証スキーマはサービスとして登録されます。
このことにより、よりコンパクトでより整理されたコードを作ることができます。
ASP.NET Core 2.0 エンドポイントを JWT でセキュアする
JWT ベースの認証を有効にしたら、HTTP
GET
リクエストで呼び出されたときに書籍のリストを返すシンプルな Web API を作りましょう。この API は以下の Controllers
名前空間の BooksController
と呼ばれる新しいクラスで保持されます。using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; namespaceJWT.Controllers { [Route("api/[controller]")] publicclassBooksController : Controller { [HttpGet, Authorize] public IEnumerable<Book> Get() { var currentUser = HttpContext.User; var resultBookList = new Book[] { new Book { Author = "Ray Bradbury",Title = "Fahrenheit 451" }, new Book { Author = "Gabriel García Márquez", Title = "One Hundred years of Solitude" }, new Book { Author = "George Orwell", Title = "1984" }, new Book { Author = "Anais Nin", Title = "Delta of Venus" } }; return resultBookList; } publicclassBook { publicstring Author { get; set; } publicstring Title { get; set; } publicbool AgeRestriction { get; set; } } } }
ご覧の通り、API は単に書籍の配列を返します。ただし、
Authorize
属性で API をマークすると、このエンドポイントに対するリクエストが HTTP リクエストで渡されたトークンの認証チェックをトリガーします。アプリケーション (IDE または
dotnet run
コマンドを通して)を実行し、 GET リクエストを /api/books
エンドポイントにするならば、応答として401
HTTP ステータスコードを取得します。 プロジェクトのソースコード に添付されている Test
プロジェクトの UnAuthorizedAccess
テストを実行するか、あるいは curl または Postman のような汎用 HTTP クライアントを使ってお試しください。もちろん、この結果はトークンが不足しているためですから API へのアクセスは拒否されます。
認証用の JWT を作成する
ユーザーが新しい JWT を得るために認証できるように、このアプリケーションに認証 API を追加しましょう。それをするに、以下のコードで
TokenController
と呼ばれるコントローラを Controllers
namespaceに作りましょう。using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace JWT.Controllers { [Route("api/[controller]")] public class TokenController : Controller { private IConfiguration _config; public TokenController(IConfiguration config) { _config = config; } [AllowAnonymous] [HttpPost] public IActionResult CreateToken([FromBody]LoginModel login) { IActionResult response = Unauthorized(); var user = Authenticate(login); if (user != null) { var tokenString = BuildToken(user); response = Ok(new { token = tokenString }); } return response; } private string BuildToken(UserModel user) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken(_config["Jwt:Issuer"], _config["Jwt:Issuer"], expires: DateTime.Now.AddMinutes(30), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } private UserModel Authenticate(LoginModel login) { UserModel user = null; if (login.Username == "mario" && login.Password == "secret") { user = new UserModel { Name = "Mario Rossi", Email = "mario.rossi@domain.com"}; } return user; } public class LoginModel { public string Username { get; set; } public string Password { get; set; } } private class UserModel { public string Name { get; set; } public string Email { get; set; } public DateTime Birthdate { get; set; } } } }
最初に気づくことは
AllowAnonymous
属性の存在です。これは、ユーザーが資格情報を提供した後に、新しいトークンを得るために誰もがアクセスできる API、つまりパブリック API でなければならないので非常に重要です。API は HTTP
POST
リクエストに応答し、ユーザー名とパスワード(LoginModel
オブジェクト)を含むオブジェクトを予測します。Authenticate
メソッドは提供されたユーザー名とパスワードが予期されたものであることを確認し、ユーザーを表す UserModel
オブジェクトを返します。もちろん、これは認証プロセスの簡易実装です。本番環境用の実装では言うまでもなく、より正確であるべきです。Authentication
メソッドがユーザーを返せば、提供された資格情報が有効であり、AuthenticationAPI は BuildToken
メソッドを通して新しいトークンを生成します。これは最も興味深い部分ですが、ここで JwtSecurityToken
クラスを使って JSON Web Token を作ります。Issuer、audience(この場合は、両方とも同じです)、有効期限および時間、および署名など、Class コンストラクタにいくつかのパラメーターを渡します。最後に、JwtSecurityTokenHandler
クラスの WriteToken
メソッドを通してそれらを変換し、BuildToken
メソッドは文字列としてトークンを返します。API へのアクセスを認証する
ここで、作成した 2 つの API をテストします。
まず、HTTP POST リクエストを
/api/token
エンドポイントに作り、以下の JSON をリクエスト本文に渡して、JWT を取得しましょう。{“username“: “mario“, “password“: “secret“}
これは、Postman またはどの HTTP クライアントでも簡単にできます。例えば、curl では以下がコマンドになります。
curl -X POST -H 'Content-Type: application/json' \ -d '{"username": "mario", "password": "secret"}' \ 0:5000/api/token
レスポンスとして、次のような JSON を取得します。
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNYXJpbyBSb3NzaSIsImVtYWlsIjoibWFyaW8ucm9zc2lAZG9tYWluLmNvbSIsImJpcnRoZGF0ZSI6IjE5ODMtMDktMjMiLCJqdGkiOiJmZjQ0YmVjOC03ZDBkLTQ3ZTEtOWJjZC03MTY4NmQ5Nzk3NzkiLCJleHAiOjE1MTIzMjIxNjgsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjM5MzkvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo2MzkzOS8ifQ.9qyvnhDna3gEiGcd_ngsXZisciNOy55RjBP4ENSGfYI" }
トークンの値を見ると、本書の始めで話し合ったように、3 つの部分はドット(.)で区切られています。
ここで、前のセクションで実行したように、書籍のリストをリクエストします。ただし、今回は認証 HTTP ヘッダーとしてトークンを提供します。
Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNYXJpbyBSb3NzaSIsImVtYWlsIjoibWFyaW8ucm9zc2lAZG9tYWluLmNvbSIsImJpcnRoZGF0ZSI6IjE5ODMtMDktMjMiLCJqdGkiOiJmZjQ0YmVjOC03ZDBkLTQ3ZTEtOWJjZC03MTY4NmQ5Nzk3NzkiLCJleHAiOjE1MTIzMjIxNjgsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjM5MzkvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo2MzkzOS8ifQ.9qyvnhDna3gEiGcd_ngsXZisciNOy55RjBP4ENSGfYI
前回と同様に、これは Postman またはどの HTTP クライアントでも簡単にできます。Curl では、以下がコマンドになります。
curl -H 'Authorization: Bearer '$JWT 0:5000/api/books
もちろん、
JWT
env 変数はJWT="eyJhbG..."
をサインインしている間に受け取ったトークンでセットしなければなりません。今回は書籍のリストを取得します。
JWT claimsを ASP.NET Core 2.0 で処理する
JWT について説明しているときに、トークンには claims と呼ばれるデータが含まれているかもしれないと言及しました。これらは通常、リソースへのアクセスを認可するときに有益になり得るユーザーについての情報です。claimsは例えば、ユーザーの電子メール、性別、役割、市町村、あるいはリソースにアクセスしているときにユーザーを識別する有益なその他の情報が考えられます。リソースにアクセスする認可をチェックしているときにclaimsが利用できるように JWT にそれらを追加できます。ASP.NET Core 2 アプリケーションでどのようにclaimsを管理するか、練習してみましょう。
このリストには、全員に適切でない書籍が含まれているとします。例えば、年齢制限のある書籍が含まれています。認証後に返される JWT にはユーザーの年齢についての情報を含むべきです。それをするには、
TokenController
の BuildToken
メソッドを以下のように更新しましょう。private string BuildToken(UserModel user) { var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.Name), new Claim(JwtRegisteredClaimNames.Email, user.Email), new Claim(JwtRegisteredClaimNames.Birthdate, user.Birthdate.ToString("yyyy-MM-dd")), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken(_config["Jwt:Issuer"], _config["Jwt:Issuer"], claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); }
前バージョンとの主な違いは
claims
変数の定義に関するものです。それはclaims
の配列インスタンスで、それぞれが鍵と値から作成されています。その鍵は 標準化されたclaims用の名前を提供するある構造の値 (JwtRegisteredClaimNames
) です。ユーザーの名前、電子メール、生年月日、および JWT に関係するユニークな識別子のclaimsを作成しました。この
claims
配列はクライアントに送信される JWT に含まれるように JwtSecurityToken
コンストラクターに渡されます。では、以下のように書籍のリストを返すときにユーザーの年齢を考慮するために、API コードを変更する方法を見てみましょう。
[Route("api/[controller]")] public class BooksController : Controller { [HttpGet, Authorize] public IEnumerable<Book> Get() { var currentUser = HttpContext.User; int userAge = 0; var resultBookList = new Book[] { new Book { Author = "Ray Bradbury", Title = "Fahrenheit 451", AgeRestriction = false }, new Book { Author = "Gabriel García Márquez", Title = "One Hundred years of Solitude", AgeRestriction = false }, new Book { Author = "George Orwell", Title = "1984", AgeRestriction = false }, new Book { Author = "Anais Nin", Title = "Delta of Venus", AgeRestriction = true } }; if (currentUser.HasClaim(c => c.Type == ClaimTypes.DateOfBirth)) { DateTime birthDate = DateTime.Parse(currentUser.Claims.FirstOrDefault(c => c.Type == ClaimTypes.DateOfBirth).Value); userAge = DateTime.Today.Year - birthDate.Year; } if (userAge < 18) { resultBookList = resultBookList.Where(b => !b.AgeRestriction).ToArray(); } return resultBookList; } public class Book { public string Author { get; set; } public string Title { get; set; } public bool AgeRestriction { get; set; } } }
AgeRestriction
プロパティを書籍クラスに追加しました。書籍に年齢が制限されているか否かを表す値はboolean値です。リクエストを受け取ると、
DateOfBirth
Claimが現在のユーザーに関係するものかをチェックします。肯定の場合は、そのユーザーの年齢を計算します。もし、そのユーザーが 18 歳未満であれば、そのリストには年齢制限なしの書籍のみがが含まれ、そうでない場合はリスト全体が返されます。この新しいシナリオは、 プロジェクトのソースコード に含まれているテストの
GetBooksWithoutAgeRestrictions
および GetBooksWithAgeRestrictions
を実行するか、あるいは以下のcurl
コマンドを発行してテストします。# サインイン curl -X POST -H 'Content-Type: application/json' -d '{username: "mary", password: "barbie"}' 0:5000/api/token # JWT 変数を設定する(AAA.BBB.CCC と受け取ったトークンと置換する) JWT="AAA.BBB.CCC" # 書籍を入手する curl -H 'Authorization: Bearer '$JWT 0:5000/api/books
最後のコマンドは、以下で制限されている以外の全ての書籍を含むリストを送信します。Delta of Venus。
“ASP.NET Core 2.0 API をセキュアにする方法を学んだばかりです。”
これをツイートする
クロス オリジンなリクエスト(CORS)を ASP.NET Core 2.0 で有効にする
多くの場合、API がその他のオリジン(その他のドメイン)から来るリクエストを受け入れるように指定します。AJAX リクエストを発行するとき、ブラウザーはプレフライトを作成し、サーバーが Web アプリをホストするドメインからのリクエストを受け入れているかをチェックします。これらプレライトの応答に、少なくともオリジナルドメインからのリクエストを受け入れることを指定する
Access-Control-Allow-Origin
ヘッダーが含まれないのであれば、ブラウザーは(セキュリティ対策のため)実際のリクエストを開始しません。CORS のサポートを含む (および、このヘッダーと一緒にいくつか追加する)には、
Startup
クラスにあと 2 つの変更を加える必要があります。最初に、以下を追加する必要がありますservices.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() .Build()); });
ConfigureServices
メソッドの最後の呼び出しとして追加します。次に、以下を加えます。app.UseCors("CorsPolicy");
これで、この API は基本的にどんなオリジンからのリクエストでもリクエストを受け入れます。さらにセキュリティを高めるには、
AllowAnyOrigin
を WithOrigins
に変更し、特定オリジン(例:https://mydomain.com
) を定義します。備考:ASP.NET Core 2.0 を Auth0 でセキュアにする
ASP.NET Core 2.0 アプリケーションを Auth0 でセキュアにすることは簡単で、たくさんの素晴らしい機能を提供します。 Auth0 を使うと数行のコード行を書くだけで、強固な ID 管理ソリューション、 シングル サインオン、 ソーシャル ID プロバイダー(Facebook、GitHub、Twitter など)のサポート、および エンタープライズ ID プロバイダー(Active Directory、LDAP、SAML、カスタムなど)のサポートすることができます。
ASP.NET Core 2.0 では、 Auth0 管理ダッシュボードに API を作成し、コードに 2 つの変更をする必要があります。API を作成するには、 無料 Auth0 アカウントにサインアップする必要があります。その後、 ダッシュボードの APIs セクションに移動し、「CREATE API」をクリックします。表示のダイアログでは、API の名前 を「Books」に、識別子を 「http://books.mycompany.com」 に設定し、署名アルゴリズム を「RS256」 のままにします。
その後、
Startup
の呼び出しを services.AddAuthentication
から以下に置換します。string domain = $"https://{Configuration["Auth0:Domain"]}/"; services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.Authority = domain; options.Audience = Configuration["Auth0:Audience"]; });
それから、以下の要素を appsettings.json に加えます。
{ "Logging": { // ... }, "Auth0": { "Domain": "bk-samples.auth0.com", "Audience": "http://books.mycompany.com" } }
注 この場合のドメインは、Auth0 アカウントを作成したときに指定したドメインに 変更されなければならないことにご注意ください 。
統合性をテストする
それだけです。ASP.NET Core 2.0 API を Auth0 でセキュアにするには、統合性をテストするだけです。ただし、この統合性をテストするには、 このアプリケーションと通信するクライアントが必要です。本書の中心は ASP.NET Core 2.0 ですから、 構成可能な Auth0 クライアントでセキュアにする汎用 Web アプリケーションを使用します。このアプリケーションで構成する必要があるのは、
clientID
、domain
、および audience
プロパティのみです。clientID
および domain
プロパティを得るには、管理ダッシュボードに新しいクライアントを作る必要があります。 Clientsセクションで「CREATE CLIENT」をクリックし、表示のダウアログで「Book Client」と名付け、クライアントタイプとして「Single Page Web Applications」を選択します。クライアントを作成した後、その「Settings」タブに移動し、http://auth0.digituz.com.br
を「Allowed Callback URLs」 フィールドに追加し、「SAVE」(ctrl/command + s) を押します。この同じタブで、興味がある両方のプロパティ(Client ID
および Domain
) をフェッチし、汎用アプリケーションに追加します。同様にaudienceに API の識別子(例:http://books.mycompany.com
) を設定できます。ここで、「SIGN IN WITH AUTH0」 を押し、ユーザーを認証します。認証した後に、Web アプリを使ってリクエストを API (例:
http://localhost:5000/api/books
) に発行します。この Web アプリが認証プロセスで生成された access_token
を自動的に Authorization
ヘッダーに追加するときに、この API はその有効性をチェックし、書籍のリストをユーザーに送信します。まとめ
本書では JSON Web Token テクノロジーの概要について説明し、ASP.NET Core 2 での使い方を紹介しました。シンプルな Web API アプリケーションを展開しながら、JWT 認証のサポートを構成する方法や認証トークンを作成する方法を見てきました。また、claimsを JWT に挿入する方法や、リソースへのアクセスを認可しながらそれらを使用する方法についても学びました。
最後に、JSON Web Tokens を ASP.NET Core 2 アプリケーションで管理することがどんなに簡単かも経験しました。
About the author
Andrea Chiarelli
Principal Developer Advocate
I have over 20 years of experience as a software engineer and technical author. Throughout my career, I've used several programming languages and technologies for the projects I was involved in, ranging from C# to JavaScript, ASP.NET to Node.js, Angular to React, SOAP to REST APIs, etc.
In the last few years, I've been focusing on simplifying the developer experience with Identity and related topics, especially in the .NET ecosystem.