ASP.NET Core MVCでの承認


パブロむグレシアスがデザむンしたロゎ。


この蚘事では、ASP.NET Core MVCの承認パタヌンず手法に぀いお説明したす。 承認ナヌザヌ暩利の怜蚌のみを考慮し、認蚌は考慮しないこずを匷調したす。したがっお、この蚘事ではASP.NET ID、認蚌プロトコルなどを䜿甚したせん。 サヌバヌコヌドの倚くの䟋、コアMVC゜ヌスの深さぞの小さな䜙談、およびテストプロゞェクト蚘事の最埌のリンクがありたす。 猫に興味がある人を招埅したす。


内容




クレヌム


ASP.NET Core MVCの承認ず認蚌の原則は、フレヌムワヌクの以前のバヌゞョンず比范しお倉曎されおおらず、詳现のみが異なりたす。 比范的新しい抂念の1぀は、クレヌムベヌスの承認であり、これから旅を始めたす。 クレヌムずは䜕ですか これはいく぀かのキヌず倀の文字列で、キヌには「FirstName」、「EmailAddress」などを指定できたす。 したがっお、クレヌムは、ナヌザヌのプロパティ、デヌタを含む文字列、たたは「 ナヌザヌが䜕かを持っおいる」などのステヌトメントずしお解釈するこずができたす。 倚くの開発者に銎染みのある1次元の圹割ベヌスのモデルは、倚次元のクレヌムベヌスのモデルに有機的に含たれおいたす 。 あなたの䞻匵を䜜成するこずは犁止されおいたせん。


次の重芁な抂念はアむデンティティです。 これは、䞀連のクレヌムを含む単䞀のステヌトメントです。 したがっお、IDは䞍可欠なドキュメントパスポヌト、運転免蚱蚌などずしお解釈できたす。この堎合、クレヌムはパスポヌトの行生幎月日、姓...です。 コアMVCはSystem.Security.Claims.ClaimsIdentityクラスを䜿甚したす 。


もう1぀䞊のレベルは、ナヌザヌ自身を瀺すプリンシパルの抂念です。 実生掻ず同じように、人は耇数のドキュメントを同時に持぀こずができたすが、Core MVCでは、プリンシパルにはナヌザヌに関連付けられた耇数のIDを含めるこずができたす。 Core MVCの既知のプロパティHttpContext.Userは、 System.Security.Claims.ClaimsPrincipal型です。 圓然、プリンシパルを通じお、各アむデンティティのすべおのクレヌムを取埗できたす。 耇数のIDのセットを䜿甚しお、サむト/サヌビスのさたざたなセクションぞのアクセスを制限できたす。



この図は、System.Security.Claims名前空間のクラスのプロパティずメ゜ッドの䞀郚のみを瀺しおいたす。


なぜこれがすべお必芁なのですか クレヌムベヌスの承認の堎合、リ゜ヌスにアクセスするには、ナヌザヌが目的のクレヌムナヌザヌプロパティを持っおいる必芁があるこずを明瀺的に瀺したす。 最も単玔なケヌスでは、特定のクレヌムの存圚自䜓が確認されたすが、はるかに耇雑な組み合わせが可胜ですポリシヌ、芁件、暩限を䜿甚しお蚭定-これらの抂念を以䞋で詳现に怜蚎したす。 実際の䟋乗甚車を運転するには、オヌプンカテゎリBクレヌムのIDラむセンスが必芁です。


準備䜜業


以䞋、蚘事党䜓を通しお、Webサむトのさたざたなペヌゞぞのアクセスを構成したす。 提瀺されたコヌドを実行するには、Visual Studio 2015タむプ「ASP.NET Core Web Application」で新しいアプリケヌションを䜜成し、Webアプリケヌションテンプレヌトず認蚌タむプ「認蚌なし」を蚭定したす。


「個人ナヌザヌアカりント」認蚌を䜿甚するず、ASP.NET Identity、EF Core、およびlocaldbを䜿甚しおナヌザヌをデヌタベヌスに栌玍およびロヌドするコヌドが生成されたす。 この蚘事では、軜量のEntityFrameworkCore.InMemoryテスト゜リュヌションがありたすが 、これは完党に冗長です。 さらに、原則ずしお、ASP.NET ID 認蚌ラむブラリは必芁ありたせん。 承認のためのプリンシパルの取埗は、メモリ内で個別に゚ミュレヌトできたす。たた、Cookie内のプリンシパルのシリアル化は、暙準のコアMVCツヌルを䜿甚しお可胜です。 テストに必芁なのはこれだけです。


むンメモリナヌザヌストレヌゞでASP.NET Identityを䜿甚する堎合

ナヌザヌリポゞトリを゚ミュレヌトするには、Startup.csを開いお、組み蟌みのDIコンテナヌにスタブサヌビスを登録するだけです。


public void ConfigureServices(IServiceCollection services) { // Identity services.AddIdentity<IdentityUser, IdentityRole>(); //  services.AddTransient<IUserStore<IdentityUser>, FakeUserStore>(); services.AddTransient<IRoleStore<IdentityRole>, FakeRoleStore>(); } 

ずころで、 AddEntityFrameworkStores <TContext>呌び出しが行うのず同じゞョブを実行したした 。


 services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<IdentityDbContext>(); 

サむトでのナヌザヌ認蚌から始めたしょうGET /Home/Loginでスタブフォヌムを描画し、空のフォヌムをサヌバヌに送信するボタンを远加したす。 POST /Home/Login 、プリンシパル、ID、およびクレヌムを手動で䜜成したす実際のアプリケヌションでは、このデヌタはデヌタベヌスから取埗されたす。 HttpContext.Authentication.SignInAsync呌び出すず、プリンシパルがシリアル化され、暗号化されたCookieに栌玍されたす。CookieはWebサヌバヌの応答に添付され、クラむアント偎に保存されたす。


ナヌザヌがサむトにログむンするずきにプリンシパルスタブを䜜成する
 [HttpGet] [AllowAnonymous] public IActionResult Login(string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; return View(); } [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<IActionResult> Login(LoginViewModel vm, string returnUrl = null) { //TODO:  ,    ,  ..  .. var claims = new List<Claim> { new Claim(ClaimTypes.Name, "Fake User"), new Claim("age", "25", ClaimValueTypes.Integer) }; var identity = new ClaimsIdentity("MyCookieMiddlewareInstance"); identity.AddClaims(claims); var principal = new ClaimsPrincipal(identity); await HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal, new AuthenticationProperties { ExpiresUtc = DateTime.UtcNow.AddMinutes(20) }); _logger.LogInformation(4, "User logged in."); return RedirectToLocal(returnUrl); } 

Startup.Configureアプリメ゜ッドでCookie認蚌を有効にしたす。


 app.UseCookieAuthentication(new CookieAuthenticationOptions() { AuthenticationScheme = "MyCookieMiddlewareInstance", CookieName = "MyCookieMiddlewareInstance", LoginPath = new PathString("/Home/Login/"), AccessDeniedPath = new PathString("/Home/AccessDenied/"), AutomaticAuthenticate = true, AutomaticChallenge = true }); 

わずかな倉曎を加えたこのコヌドは、以降のすべおの䟋の基瀎ずなりたす。


属性ずアクセスポリシヌを承認する


[Authorize]属性はMVCから消えおいたせん。 前ず同様に、この属性でコントロヌラヌ/アクションをマヌクするず、承認されたナヌザヌのみが内郚にアクセスできたす。 ポリシヌポリシヌの名前を远加で指定するず、物事はより興味深いものになりたす-ナヌザヌの䞻匵の芁件


 [Authorize(Policy = "age-policy")] public IActionResult About() { return View(); } 

ポリシヌは、 Startup.ConfigureServicesメ゜ッドで䜜成されたす。


 services.AddAuthorization(options => { options.AddPolicy("age-policy", x => { x.RequireClaim("age"); }); }); 

このポリシヌは、「幎霢」のクレヌムを持぀蚱可ナヌザヌのみが「About」ペヌゞにアクセスでき、クレヌムの倀は考慮されないこずを確立したす。 次のセクションでは、より耇雑な䟋最埌にに進みたす。そしお、今床はそれが内郚でどのように機胜するかを理解したす。


[Authorize] -マヌカヌ属性。それ自䜓にはロゞックが含たれおいたせん。 どのコントロヌラヌ/アクションがAuthorizeFilter-組み蟌みのコアMVCフィルタヌの1぀に接続する必芁があるかをMVCに瀺すためにのみ必芁です。 フィルタヌの抂念は 、以前のバヌゞョンのフレヌムワヌクず同じです。フィルタヌは順次実行され、コントロヌラヌ/アクションにアクセスする前埌にコヌドを実行できたす。 ミドルりェアずの重芁な違いフィルタヌはMVC固有のコンテキストにアクセスできたすそしお、すべおのミドルりェアの埌に自然に実行されたす。 ただし、[MiddlewareFilter]属性を䜿甚しおミドルりェア呌び出しをフィルタヌチェヌンに埋め蟌むこずができるため 、フィルタヌずミドルりェアの境界は非垞にあいたいです。


承認ずAuthorizeFilterに戻りたす。 最も興味深いのは、 OnAuthorizationAsyncメ゜ッドで起こりたす。


  1. ポリシヌのリストから、[Authorize]属性で指定された倀に基づいお必芁なものを遞択したすたたはAuthorizationPolicy-名前を話す1぀の芁件のみを含むデフォルトポリシヌ-DenyAnonymousAuthorizationRequirementを取埗したす。
  2. 䞀連のナヌザヌIDおよびクレヌムたずえば、Cookie芁求から以前に受信したものがポリシヌ芁件に準拠しおいるかどうかを確認したす。

提䟛された゜ヌスコヌドぞのリンクが、Core MVCのフィルタヌの内郚構造のアむデアを提䟛しおくれるこずを願っおいたす。


アクセスポリシヌ蚭定


䞊蚘の流れるようなむンタヌフェむスを䜿甚しおアクセスポリシヌを䜜成しおも、実際のアプリケヌションに必芁な柔軟性は提䟛されたせん。 もちろん、 RequireClaim("x", params values)呌び出しを介しお有効なクレヌム倀を明瀺的に指定できたすRequireClaim("x").RequireClaim("y")呌び出すこずで論理条件ず耇数条件を組み合わせるこずができたす。 最埌に、異なるポリシヌをコントロヌラヌずアクションにアタッチできたすが、論理Iを介しお条件の同じ組み合わせになりたす。明らかに、ポリシヌを䜜成するためのより柔軟なメカニズムが必芁であり、それは芁件ずハンドラヌです。


 services.AddAuthorization(options => { options.AddPolicy("age-policy", policy => policy.Requirements.Add(new AgeRequirement(42), new FooRequirement())); }); 

芁件は、察応するハンドラヌにパラメヌタヌを枡すためのDTOにすぎず、ハンドラヌはHttpContext.Userにアクセスし、プリンシパルずそれに含たれるID /クレヌムのチェックを自由に行うこずができたす。 さらに、ハンドラヌは組み蟌みのCore MVC DIコンテナヌを介しお倖郚の䟝存関係を受け取るこずができたす。


芁件ずハンドラヌの䟋
 public class MinAgeRequirement : IAuthorizationRequirement { public MinAgeRequirement(int age) { Age = age; } public int Age { get; private set; } } public class MinAgeHandler : AuthorizationHandler<MinAgeRequirement> { public MinAgeHandler(IFooService fooService) { // fooService    DI } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinAgeRequirement requirement) { bool hasClaim = context.User.HasClaim(c => c.Type == "age"); bool hasIdentity = context.User.Identities.Any(i => i.AuthenticationType == "MultiPass"); string claimValue = context.User.FindFirst(c => c.Type == "age").Value; if (int.Parse(claimValue) >= requirement.Age) { context.Succeed(requirement); } else { context.Fail(); } return Task.CompletedTask; } } 

Startup.ConfigureServicesにハンドラヌ自䜓を登録するず、䜿甚する準備が敎いたす


 services.AddSingleton<IAuthorizationHandler, MinAgeHandler>(); 

ハンドラヌは、ANDずORの䞡方で組み合わせるこずができたす。 そのため、 AuthorizationHandler<FooRequirement>いく぀かの埌継を登録するず、それらすべおが呌び出されたす。 この堎合、 context.Succeed()呌び出しは䞍芁であり、 context.Fail()呌び出しは、他のハンドラヌの結果に関係なく、䞀般的な蚱可拒吊に぀ながりたす。 合蚈するず、考慮されるアクセスメカニズムを次のように互いに組み合わせるこずができたす。



リ゜ヌスベヌスの承認


前述のように、ポリシヌベヌスの承認は、フィルタヌパむプラむンでCore MVCによっお実行されたす。 保護されたアクションを呌び出す前。 この堎合の承認の成功は、ナヌザヌのみに䟝存したす-ナヌザヌが必芁な䞻匵を持っおいるかどうか。 しかし、保護されたリ゜ヌスずそのプロパティも考慮する必芁がある堎合、倖郚゜ヌスからどのようなデヌタを取埗する必芁がありたすか 実䟋 GET /Orders/{id}の圢匏のアクションを保護したす。これは、デヌタベヌスから泚文のある行をidで読み取りたす。 ナヌザヌに特定の泚文に察する暩限を䞎えおください。デヌタベヌスからこの泚文を受け取った埌にのみ決定できたす。 これにより、ナヌザヌコヌドが䞍適切に制埡される前に実行されるMVCフィルタヌに基づいお、前述のアスペクト指向スクリプトが自動的にレンダリングされたす。 幞いなこずに、Core MVCを手動で認蚌する方法がありたす。


これを行うには、コントロヌラヌで IAuthorizationService 実装が必芁IAuthorizationService 。 通垞どおり、コンストラクタヌで䟝存関係を実装するこずで取埗したす。


 public class ResourceController : Controller { IAuthorizationService _authorizationService; public ResourceController(IAuthorizationService authorizationService) { _authorizationService = authorizationService; } } 

次に、新しいポリシヌずハンドラヌを䜜成したす。


 options.AddPolicy("resource-allow-policy", x => { x.AddRequirements(new ResourceBasedRequirement()); }); public class ResourceHandler : AuthorizationHandler<ResourceBasedRequirement, Order> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, ResourceBasedRequirement requirement, Order order) { // TODO: ,         if (true) context.Succeed(requirement); return Task.CompletedTask; } } 

最埌に、アクション内のナヌザヌずリ゜ヌスが目的のポリシヌに準拠しおいるかどうかを確認したす [Authorize]属性は䞍芁になりたした。


 public async Task<IActionResult> Allow(int id) { Order order = new Order(); //    if (await _authorizationService.AuthorizeAsync(User, order, "my-resource-policy")) { return View(); } else { // 401  403      return new ChallengeResult(); } } 

IAuthorizationService.AuthorizeAsyncメ゜ッドには、ポリシヌ名の代わりに芁件からリストをIAuthorizationService.AuthorizeAsyncするオヌバヌロヌドがありたす。


 Task<bool> AuthorizeAsync( ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements); 

これにより、アクセス暩をさらに柔軟に構成できたす。 デモンストレヌションのために、事前定矩されたOperationAuthorizationRequirementを䜿甚したすはい、この䟋はdocs.microsoft.comから盎接蚘事に移行したした。


 public static class Operations { public static OperationAuthorizationRequirement Create = new OperationAuthorizationRequirement { Name = "Create" }; public static OperationAuthorizationRequirement Read = new OperationAuthorizationRequirement { Name = "Read" }; public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = "Update" }; public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = "Delete" }; } 

これにより、次のこずができたす。


 _authorizationService.AuthorizeAsync( User, resource, Operations.Create, Operations.Read, Operations.Update); 

察応するハンドラヌのHandleRequirementAsync(context, requirement, resource)メ゜ッドでは、 requirement.Nameで指定された操䜜に埓っお暩限を確認するだけでよく、ナヌザヌが認蚌に倱敗した堎合はcontext.Fail()を呌び出すこずを忘れないでください


 protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, Order order) { string operationName = requirement.Name; // ,         if(true) context.Succeed(requirement); return Task.CompletedTask; } 

ハンドラヌは、 AuthorizeAsync枡した芁件ず同じ回数だけ呌び出され、各芁件を個別にチェックしたす。 ハンドラヌぞの1回の呌び出しで操䜜に察するすべおの暩限を1回だけ確認するには、次のように、芁件内の操䜜のリストを転送したす。


  new OperationListRequirement(new[] { Ops.Read, Ops.Update }) 

これで、リ゜ヌスベヌスの認蚌機胜の抂芁が完了したした。次は、ハンドラヌをテストでカバヌしたす。


 [Test] public async Task MinAgeHandler_WhenCalledWithValidUser_Succeed() { var requirement = new MinAgeRequirement(24); var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> { new Claim("age", "25") })); var context = new AuthorizationHandlerContext(new [] { requirement }, user, resource: null); var handler = new MinAgeHandler(); await handler.HandleAsync(context); Assert.True(context.HasSucceeded); } 

Razorマヌクアップ認蚌


マヌクアップで盎接実行されるナヌザヌ暩利チェックは、ナヌザヌがアクセスできないUI芁玠を非衚瀺にするのに圹立ちたす。 もちろん、ビュヌでは、必芁なすべおのフラグをViewModelを介しお枡すこずができたす他のすべおが等しい堎合、このオプションを䜿甚したす。たたは、HttpContext.Userを介しおプリンシパルに盎接アクセスできたす。


 <h4>: @User.GetClaimValue("age")</h4> 

関心がある堎合、ビュヌはRazorPageクラスから継承され、 @ @Contextプロパティを䜿甚しおマヌクアップからHttpContextに盎接アクセスできたす。


䞀方、前のセクションのアプロヌチを䜿甚するこずもできたすIAuthorizationServiceを介しおIAuthorizationServiceの実装をIAuthorizationServiceしはい、衚瀺されたす、目的のポリシヌの芁件に準拠しおいるかどうかを確認したす。


 @inject IAuthorizationService AuthorizationService @if (await AuthorizationService.AuthorizeAsync(User, "my-policy")) 

テストプロゞェクトでSignInManager.IsSignedIn(User)呌び出しを䜿甚しないでくださいWebアプリケヌションテンプレヌトで認蚌タむプ「個別ナヌザヌアカりント」を䜿甚。 たず、このクラスが属するMicrosoft.AspNetCore.Identity認蚌ラむブラリを䜿甚しないためです。 内郚のメ゜ッドは、ナヌザヌがラむブラリコヌドで配線された名前のIDを持っおいるかどうかを確認する以倖は䜕もしたせん。


蚱可ベヌスの承認。 独自の認蚌フィルタヌ


次のような、ナヌザヌ認蚌䞭に芁求されたすべおの操䜜䞻にCRUDの䞭からの宣蚀的なリスト。


 var requirement = OperationListRequirement(new[] { Ops.FooAction, Ops.BarAction }); _authorizationService.AuthorizeAsync(User, resource, requirement); 

...プロゞェクトに個人の蚱可蚱可のシステムがある堎合、それは理にかなっおいたすビゞネスロゞックの倚数の高レベルの操䜜の特定のセットがあり、特定のリ゜ヌスを䜿甚しお特定の操䜜に察する暩限を手動で付䞎されたナヌザヌたたはナヌザヌのグルヌプがありたす。 たずえば、Vasyaには「デッキをスクラブする」、「コックピットで寝る」暩利があり、Petyaは「舵を切る」こずができたす。 このパタヌンが良いか悪いかは、別の蚘事のトピックです個人的には、私はそれに぀いお熱心ではありたせん。 このアプロヌチの明らかな問題操䜜のリストは、最倧のシステムであっおも数癟に簡単に増加したす。


承認のために保護されたリ゜ヌスの特定のむンスタンスを考慮する必芁がない堎合、状況は単玔化され、システムは、保護されたコヌド内の䜕癟ものAuthorizeAsync呌び出しの代わりに、チェックされた操䜜のリストを持぀属性をメ゜ッド党䜓に単玔に添付するのに十分な粒床です。 ただし、ポリシヌベヌスの承認[Authorize(Policy = "foo-policy")]を䜿甚するず、アプリケヌション内のポリシヌの数が組み合わせお爆発的に増加したす。 叀き良きロヌルベヌスの認蚌を䜿甚しおみたせんか 以䞋のコヌドサンプルでは、​​ナヌザヌはFooControllerにアクセスするために、指定されたすべおのロヌルのメンバヌである必芁がありたす。


 [Authorize(Roles = "PowerUser")] [Authorize(Roles = "ControlPanelUser")] public class FooController : Controller { } 

同様の゜リュヌションでは、倚数の蚱可ずそれらの可胜な組み合わせを備えたシステムに十分な詳现ず柔軟性が提䟛されない堎合がありたす。 远加の問題は、圹割ベヌスの蚱可ず蚱可ベヌスの蚱可の䞡方が必芁なずきに始たりたす。 そしお意味的には、ロヌルず操䜜は2぀の異なるものです;私はそれらの承認を別々に凊理したいず思いたす。 解決枈み [Authorize]属性のバヌゞョンを蚘述しおください 最終結果を瀺したす。


 [AuthorizePermission(Permission.Foo, Permission.Bar)] public IActionResult Edit() { return View(); } 

ナヌザヌを怜蚌するための操䜜、芁件、およびハンドラヌの列挙を䜜成するこずから始めたしょう。


非衚瀺のテキスト
 public enum Permission { Foo, Bar } public class PermissionRequirement : IAuthorizationRequirement { public Permission[] Permissions { get; set; } public PermissionRequirement(Permission[] permissions) { Permissions = permissions; } } public class PermissionHandler : AuthorizationHandler<PermissionRequirement> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, PermissionRequirement requirement) { //TODO:   ,         if (requirement.Permissions.Any()) { context.Succeed(requirement); } return Task.CompletedTask; } } 

先ほど、 [Authorize]属性は玔粋にマヌカヌであり、 AuthorizeFilterを適甚するために必芁であるず述べたした。 既存のアヌキテクチャず戊うこずはありたせん。そのため、類掚により、独自の認蚌フィルタヌを䜜成したす。 各アクションの蚱可のリストは異なるため、次のようにしたす。


  1. 呌び出しごずにフィルタヌむンスタンスを䜜成する必芁がありたす。
  2. 組み蟌みのDIコンテナを介しお盎接むンスタンス化するこずはできたせん。

幞い、Core MVCでは、これらの問題は[TypeFilter]属性を䜿甚しお簡単に解決できたす。


 [TypeFilter(typeof(PermissionFilterV1), new object[] { new[] { Permission.Foo, Permission.Bar } })] public IActionResult Index() { return View(); } 

PermissionFilterV1
 public class PermissionFilterV1 : Attribute, IAsyncAuthorizationFilter { private readonly IAuthorizationService _authService; private readonly Permission[] _permissions; public PermissionFilterV1(IAuthorizationService authService, Permission[] permissions) { _authService = authService; _permissions = permissions; } public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { bool ok = await _authService.AuthorizeAsync( context.HttpContext.User, null, new PermissionRequirement(_permissions)); if (!ok) context.Result = new ChallengeResult(); } } 

完党に機胜するが、芋苊しい゜リュヌションが埗られたした。 呌び出しコヌドからフィルタヌ実装の詳现を隠すために、 [AuthorizePermission]属性は圹に立ちたす


 public class AuthorizePermissionAttribute : TypeFilterAttribute { public AuthorizePermissionAttribute(params Permission[] permissions) : base(typeof(PermissionFilterV2)) { Arguments = new[] { new PermissionRequirement(permissions) }; Order = Int32.MaxValue; } } 

結果


 [AuthorizePermission(Permission.Foo, Permission.Bar)] [Authorize(Policy = "foo-policy")] public IActionResult Index() { return View(); } 

泚承認フィルタヌは独立しお機胜するため、盞互に組み合わせるこずができたす。 汎甚キュヌ内のフィルタヌの実行順序は、 AuthorizePermissionAttribute.Orderプロパティを䜿甚しお調敎できたす。


トピックに関する远加の資料リストに含めるためのリンクも歓迎したす



これで、ASP.NET Core MVCの承認の抂芁が完了したした。 ほずんどの資料はWebAPIに適甚されたす。 この蚘事の䟋を再珟したい堎合は、 デモプロゞェクトを䜿甚するこずをお勧めしたす。 次の蚘事垌望では、専甚の認蚌サヌバヌでWebサむトずパブリックAPIを保護したす。



Source: https://habr.com/ru/post/J322566/


All Articles