
ãããã€ã°ã¬ã·ã¢ã¹ããã¶ã€ã³ããããŽã
ãã®èšäºã§ã¯ã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) {
ãšããã§ã 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ã¡ãœããã§èµ·ãããŸãã
- ããªã·ãŒã®ãªã¹ãããã[Authorize]å±æ§ã§æå®ãããå€ã«åºã¥ããŠå¿
èŠãªãã®ãéžæããŸãïŒãŸãã¯AuthorizationPolicy-ååã話ã1ã€ã®èŠä»¶ã®ã¿ãå«ãããã©ã«ãããªã·ãŒ-DenyAnonymousAuthorizationRequirementãååŸããŸãïŒã
- äžé£ã®ãŠãŒã¶ãŒ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()
åŒã³åºãã¯ãä»ã®ãã³ãã©ãŒã®çµæã«é¢ä¿ãªããäžè¬çãªèš±å¯æåŠã«ã€ãªãããŸãã åèšãããšãèæ
®ãããã¢ã¯ã»ã¹ã¡ã«ããºã ã次ã®ããã«äºãã«çµã¿åãããããšãã§ããŸãã
- ããªã·ãŒïŒAND
- èŠä»¶ïŒAND
- ãã³ãã©ãŒïŒAND / ORã
ãªãœãŒã¹ããŒã¹ã®æ¿èª
åè¿°ã®ããã«ãããªã·ãŒããŒã¹ã®æ¿èªã¯ããã£ã«ã¿ãŒãã€ãã©ã€ã³ã§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) {
æåŸã«ãã¢ã¯ã·ã§ã³å
ã®ãŠãŒã¶ãŒãšãªãœãŒã¹ãç®çã®ããªã·ãŒã«æºæ ããŠãããã©ããã確èªããŸãïŒ [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) {
å
ã»ã©ã [Authorize]
å±æ§ã¯çŽç²ã«ããŒã«ãŒã§ããã AuthorizeFilter
ãé©çšããããã«å¿
èŠã§ãããšè¿°ã¹ãŸããã æ¢åã®ã¢ãŒããã¯ãã£ãšæŠãããšã¯ãããŸããããã®ãããé¡æšã«ãããç¬èªã®èªèšŒãã£ã«ã¿ãŒãäœæããŸãã åã¢ã¯ã·ã§ã³ã®èš±å¯ã®ãªã¹ãã¯ç°ãªãããã次ã®ããã«ããŸãã
- åŒã³åºãããšã«ãã£ã«ã¿ãŒã€ã³ã¹ã¿ã³ã¹ãäœæããå¿
èŠããããŸãã
- çµã¿èŸŒã¿ã®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ãä¿è·ããŸãã