
æè¿ãASP.NET Coreã®OpenId Connectã§èªèšŒãã©ã®ããã«è¡ãããããçè§£ããå¿
èŠããããŸããã äŸããå§ããŠã仿§ãèªãããšã¯é¿ããããªãããšãããã«æããã«ãªãããœãŒã¹ã³ãŒããšéçºè
ã®èšäºãèªãå¿
èŠããããŸããã ãã®çµæãASP.NET Coreãã©ãããã©ãŒã ã§OpenId Connect Implicit Flowã®å®çšçãªå®è£
ãäœæããæ¹æ³ãçè§£ããããã«å¿
èŠãªãã¹ãŠã1ãæã«éããããšããèŠæããããŸããã
ãã®èšäºã¯å®è£
ã®è©³çްã«é¢ãããã®ãªã®ã§ãèšäºã§ææ¡ãããŠããã³ãŒãã«åŸã£ãŠãœãªã¥ãŒã·ã§ã³ãåçŸããããšããå§ãããŸããããããªããšãã³ã³ããã¹ããææ¡ããããšãå°é£ã«ãªããŸãã ã³ã¡ã³ãããã³èšäºã®æ¬æã«ããéèŠãªã³ã¡ã³ãã®ã»ãšãã©ã«ã¯ããœãŒã¹ãžã®ãªã³ã¯ãå«ãŸããŠããŸãã äžéšã®çšèªã¯ãäžè¬çã«ãã·ã¢èªãžã®ç¿»èš³ãåãå
¥ããŠããªããããè±èªã®ãŸãŸã«ããŸããã
OpenId Connectã«ã€ããŠå°ã
OpenId Connectãçè§£ããŠããã°ã次ã®ããŒãããèªã¿å§ããããšãã§ããŸãã
OpenId ConnectïŒOpenIdãšæ··åããªãã§ãã ããïŒã¯ãOAuth2.0æ¿èªãããã³ã«ã«åºã¥ããŠæ§ç¯ãããèªèšŒãããã³ã«ã§ãã å®éãOAuth2ã¿ã¹ã¯ã«ã¯ãŠãŒã¶ãŒã®æ¿èªã®ã¿ãå«ãŸããèªèšŒã¯å«ãŸããŸããã OpenID Connectã¯ãã¯ã¬ãŒã ãšåŒã°ããå€ã®ã»ãããšããŠãŠãŒã¶ãŒãããã¡ã€ã«ãååŸããã³è¡šç€ºããæšæºçãªæ¹æ³ãå®çŸ©ããŠããŸãã OpenId Connectã¯ããã®æ
å ±ãè¿ãUserInfoãšã³ããã€ã³ããèšè¿°ããŸãã ãŸããã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã¯ã眲åãããJSON WebããŒã¯ã³ïŒ JWT ïŒã®åœ¢åŒã§ãŠãŒã¶ãŒæ
å ±ãåä¿¡ã§ããããããµãŒããŒã«éä¿¡ãããªã¯ãšã¹ããæžããããšãã§ããŸãã
å
¬åŒãµã€ãã®ãããã³ã«ã«æ
£ããã®ã¯çã«ããªã£ãŠããŸããConnect2id ã Auth0ãStormpathãªã©ã®ã¯ã©ãŠãããŒã¹ã®èªèšŒãœãªã¥ãŒã·ã§ã³ã®åçšãããã€ããŒã®ãµã€ããèªããšäŸ¿å©ã§ãã å¿
èŠãªãã¹ãŠã®çšèªã®èª¬æã¯è¡ããŸããããŸããããã¹ãã®å£ã«ãªããŸããæ¬¡ã«ãå¿
èŠãªãã®ã¯ãã¹ãŠãããã®ãªã³ã¯ã«ãããŸãã
Identity Serverã«æ
£ããŠããªãå Žåã¯ãåªããããã¥ã¡ã³ããšãã®ãããªçŽ æŽãããäŸãèªãããšããå§ããããšããå§ãããŸãã
çµæãšããŠäœãåŸããã§ãã
OpenId Connect Implicit Flowãå®è£
ããŸããããã¯ãSPAãå«ããã©ãŠã¶ãŒã®JavaScriptã¢ããªã±ãŒã·ã§ã³ã«æšå¥šãããŸãã ãã®ããã»ã¹ã§ã¯ããŠã©ãŒã¯ã¹ã«ãŒã§éåžžè¡ãããããšãããå°ãæ·±ããããŸããŸãªéèŠãªèšå®ã«ã€ããŠèª¬æããŸãã æ¬¡ã«ãOpenId Connectãããã³ã«ã®èгç¹ããå®è£
ãã©ã®ããã«æ©èœãããã確èªããå®è£
ããããã³ã«ã«ã©ã®ããã«é¢é£ãããã調ã¹ãŸãã
ããŒã«
- ãµãŒããŒåŽã§ã¯ã IdentityServer4ã䜿çšããŸã
- ã¯ã©ã€ã¢ã³ãåŽã§ã¯ã oidc-clientã©ã€ãã©ãªã䜿çšããŸã
äž¡æ¹ã®ã©ã€ãã©ãªã®äž»ãªèè
ã¯ã Brock AllenãšDominic Brierã§ãã
çžäºäœçšã®ã·ããªãª
3ã€ã®ãããžã§ã¯ãããããŸãã
- IdentityServerã¯ãOpenId ConnectèªèšŒãµãŒããŒã§ãã
- Apiã¯ãã¹ãWebãµãŒãã¹ã§ãã
- Clientã¯ã JavaScriptClientã³ãŒãã«åºã¥ããJavaScriptã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã§ãã
察話ã®ã·ããªãªã¯æ¬¡ã®ãšããã§ããã¯ã©ã€ã¢ã³ãã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã¯IdentityServerèªèšŒãµãŒããŒã§èªèšŒãããaccess_tokenïŒJWTïŒãåä¿¡ããŸããããã¯ã ApiãµãŒããŒã§WebãµãŒãã¹ãåŒã³åºããã¢ã©ãŒããŒã¯ã³ãšããŠäœ¿çšãããŸãã
OpenId Connectæšæºã§ã¯ãããŸããŸãªèªèšŒæé ã説æãããŠããŸãã æšæºèšèªã®ãããã®ãªãã·ã§ã³ã¯ããããŒãšåŒã°ããŸãã
ãã®èšäºã§æ€èšããæé»çãªãããŒã«ã¯ã æ¬¡ã®æé ãå«ãŸããŸã ã
- ã¯ã©ã€ã¢ã³ãã¯ãç®çã®èŠæ±ãã©ã¡ãŒã¿ãŒãå«ãèªèšŒèŠæ±ãæºåããŸãã
- ã¯ã©ã€ã¢ã³ã㯠ãèªèšŒ ãµãŒããŒã« èªèšŒèŠæ±ãéä¿¡ã ãŸã ã
- èªå¯ãµãŒããŒã¯ãšã³ããŠãŒã¶ãŒãèªèšŒããŸã ã
- èªå¯ãµãŒããŒã¯ã ãšã³ããŠãŒã¶ãŒãã確èªãåãåããŸã ã
- èš±å¯ãµãŒããŒã¯ ãid_tokenããã³å¿
èŠã«å¿ããŠaccess_tokenã䜿çšããŠã ãšã³ããŠãŒã¶ãŒãã¯ã©ã€ã¢ã³ãã«éãè¿ããŸã ã
- ã¯ã©ã€ã¢ã³ãã¯id_tokenãæ€èšŒãã ãšã³ããŠãŒã¶ãŒã® ãµããžã§ã¯ãèå¥åãåãåããŸã ã

å®è£
ãã°ã€ã³ãšãã°ã¢ãŠãã«é¢é£ããããŒãžã®èšè¿°ã倧å¹
ã«ç¯çŽããããã«ã å
¬åŒã®ã¯ã€ãã¯ã¹ã¿ãŒãã³ãŒãã䜿çšããŸã ã
ãã®æŒç¿ã§ã¯ã ApiãšIdentityServerãdotnet run
ããšããå§ããdotnet run
ãIdentityServerã¯äœæ¥äžã«å€ãã®æçšãªèšºææ
å ±ãæžã蟌ã¿ãŸãããã®æ
å ±ã¯ããã«ã³ã³ãœãŒã«ã«è¡šç€ºãããŸãã
ç°¡åã«ããããã«ããŠãŒã¶ãŒã®ãã©ãŠã¶ãŒãå®è¡ãããŠããã³ã³ãã¥ãŒã¿ãŒãšåãã³ã³ãã¥ãŒã¿ãŒã§ãã¹ãŠã®ãããžã§ã¯ããå®è¡ãããŠãããšæ³å®ããŠããŸãã
å§ããŸãããã æç¢ºã«ããããã«ãVisual Studio 2017ïŒ15.3ïŒã䜿çšããŠãããšä»®å®ããŸãã 宿ãããœãªã¥ãŒã·ã§ã³ã³ãŒãã¯ãã¡ãã§ç¢ºèªã§ããŸã
空ã®OpenIdConnectSampleãœãªã¥ãŒã·ã§ã³ãäœæããŸãã
ã»ãšãã©ã®ã³ãŒãã¯IdentityServerã®ããã¥ã¡ã³ãã®ãµã³ãã«ã«åºã¥ããŠããŸããããã®èšäºã®ã³ãŒãã¯ãå
¬åŒããã¥ã¡ã³ãã«æ¬ ããŠãããã®ã§è£è¶³ãããæ³šéãä»ããããŠããŸãã
ãã¹ãŠã®å
¬åŒã®äŸãããçè§£ããããšããå§ãããŸãããæé»çãªãããŒã«ã€ããŠè©³ããèŠãŠãããŸãã
1. IdentityServer
空ã®ãããžã§ã¯ãã§ãœãªã¥ãŒã·ã§ã³ãäœæãããã©ãããã©ãŒã ãšããŠASP.NET Core 1.1ãéžæããŸãã
ãããã®NuGetããã±ãŒãžãã€ã³ã¹ããŒã«ãã
Install-Package Microsoft.AspNetCore.Mvc -Version 1.1.3 Install-Package Microsoft.AspNetCore.StaticFiles -Version 1.1.2 Install-Package IdentityServer4 -Version 1.5.2
ããã±ãŒãžã®ããŒãžã§ã³ã¯ããã§éèŠã§ã Install-Package
ã¯ãããã©ã«ãã§ææ°ããŒãžã§ã³ãã€ã³ã¹ããŒã«ããŸãã èè
ã¯ãdevãã©ã³ãã®Asp.NET Core 2.0ã«ãã§ã«IdentityServerããŒããäœæããŠããŸããããå·çæç¹ã§ã¯ããŸã Quickstart UIãç§»æ€ããŠããŸããã§ããã .NET Core 1.1ãš2.0ã®ãµã³ãã«ã³ãŒãã®éãã¯ãããã§ãã
Main
Program.csã¡ãœãããæ¬¡ã®ããã«å€æŽããŸã
public static void Main(string[] args) { Console.Title = "IdentityServer"; // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x var host = new WebHostBuilder() .UseKestrel() // , Kestrel .UseUrls("http://localhost:5000") // UI - .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); }
ãã®åŸã Startup.csã§
- åå空éã远å ãã
using System.Security.Claims; using IdentityServer4; using IdentityServer4.Configuration; using IdentityServer4.Models; using IdentityServer4.Test;
- IdentityServerèšå®ãå«ãããã€ãã®ãã«ããŒã¡ãœããã远å ããã³ã¡ã³ãã«æ³šæããŠãã ããã ãããã®ã¡ãœããã¯ãåŸã§
ConfigureServices
ã§åŒã³åºãããŸãã ãããžã§ã¯ãã«ã¡ãœããã远å ããåã«ã¡ãœããã®ããã¹ããèªãããšããå§ãããŸã-äžæ¹ã§ãããã«ãããäœãèµ·ãã£ãŠããã®ããå
šäœçã«ææ¡ã§ããããã«ãªããŸããäžæ¹ã§ãäœèšãªããšã¯ããŸããããŸããã
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã®æ
å ±èšå®
public static IEnumerable<IdentityResource> GetIdentityResources() { // , scopes IdentityServer return new List<IdentityResource> { // "sub" claim new IdentityResources.OpenId(), // claims profile scope // http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims new IdentityResources.Profile(), }; }
ãããã®èšå®ã¯Claim sub
ãµããŒãã远å ããŸããããã¯ãOpenId ConnectããŒã¯ã³ãããã³ååãæ§å¥ãçå¹Žææ¥ãªã©ã®OpenId Connectæšæºã§èšè¿°ããããããã¡ã€ã«ãã£ãŒã«ããå«ãã¯ã¬ãŒã ã¹ã³ãŒãprofile
ãšäžèŽããããã®æå°èŠä»¶ã§ãã
ããã¯ä»¥åã®èšå®ã«äŒŒãŠããŸãããæ
å ±ã¯APIã察象ãšããŠããŸã
public static IEnumerable<ApiResource> GetApiResources() { // claims scopes access_token return new List<ApiResource> { // scope "api1" IdentityServer new ApiResource("api1", "API 1", // claims scope api1 new[] {"name", "role" }) }; }
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³èªäœããµãŒããŒã«ã€ããŠç¥ãå¿
èŠããããŸã
public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { // , client_id ClientId = "js", ClientName = "JavaScript Client", AllowedGrantTypes = GrantTypes.Implicit, AllowAccessTokensViaBrowser = true, // , // false UserInfo endpoint AlwaysIncludeUserClaimsInIdToken = true, // // User Agent, RedirectUris = { // "http://localhost:5003/callback.html", // access_token iframe "http://localhost:5003/callback-silent.html" }, PostLogoutRedirectUris = { "http://localhost:5003/index.html" }, // , CORS- AllowedCorsOrigins = { "http://localhost:5003" }, // scopes, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api1" }, AccessTokenLifetime = 3600, // , IdentityTokenLifetime = 300, // , // refresh- scope offline_access AllowOfflineAccess = false, } }; }
ãã¹ããŠãŒã¶ãŒã ããã«ã¯ç®¡çè
ãããããšã«æ³šæããŠãã ãã
public static List<TestUser> GetUsers() { return new List<TestUser> { new TestUser { SubjectId = "1", Username = "alice", Password = "password", Claims = new List<Claim> { new Claim("name", "Alice"), new Claim("website", "https://alice.com"), new Claim("role", "user"), } }, new TestUser { SubjectId = "2", Username = "bob", Password = "password", Claims = new List<Claim> { new Claim("name", "Bob"), new Claim("website", "https://bob.com"), new Claim("role", "admin"), } } }; }
ConfigureServices
ã¡ãœããã倿ŽããŸã
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddIdentityServer(options => { // http://docs.identityserver.io/en/release/reference/options.html#refoptions options.Endpoints = new EndpointsOptions { // Implicit Flow EnableAuthorizeEndpoint = true, // EnableCheckSessionEndpoint = true, // EnableEndSessionEndpoint = true, // claims // http://openid.net/specs/openid-connect-core-1_0.html#UserInfo EnableUserInfoEndpoint = true, // OpenId Connect EnableDiscoveryEndpoint = true, // , EnableIntrospectionEndpoint = false, // .. Implicit Flow access_token authorization_endpoint EnableTokenEndpoint = false, // refresh reference tokens // http://docs.identityserver.io/en/release/topics/reference_tokens.html EnableTokenRevocationEndpoint = false }; // IdentitySever cookie options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions { CookieLifetime = TimeSpan.FromDays(1) }; }) // x509-, IdentityServer RS256 JWT .AddDeveloperSigningCredential() // id_token .AddInMemoryIdentityResources(GetIdentityResources()) // access_token .AddInMemoryApiResources(GetApiResources()) // .AddInMemoryClients(GetClients()) // .AddTestUsers(GetUsers()); }
ãã®æ¹æ³ã§ã¯ã IdentityServerèšå®ãç¹ã«ããŒã¯ã³ã®çœ²åã«äœ¿çšãããèšŒææžãOpenId ConnectãšOAuth2.0ã®æå³ã§ã®scope
èšå®ãã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³èšå®ãããã³ãŠãŒã¶ãŒèšå®ãæå®ããŸãã
ããå°ãã AddIdentityServer
ã¯ã IdentityServerãµãŒãã¹ãASP.NET CoreäŸåé¢ä¿è§£æ±ºã¡ã«ããºã ã«ç»é²ããŸãAddIdentityServer
ããã«ãŠã§ã¢ãšããŠè¿œå ããã«ã¯ããããè¡ãå¿
èŠããããŸãã
- IdentityServer㯠RSA SHA 256ã䜿çšããŠããŒã¯ã³ã«çœ²åãããããç§å¯éµãšå
¬ééµã®ãã¢ãå¿
èŠã§ãã
AddDeveloperSigningCredential
ã¯ãJWTããŒã¯ã³ã«çœ²åããããã®ãã¹ãããŒãã€ãŸãããã®å Žåid_token ã AddDeveloperSigningCredential
远å ããŸãã æ¬çªç°å¢ã§ã¯ããããã®ããŒã眮ãæããå¿
èŠããããŸããããšãã°ã èªå·±çœ²åèšŒææžãçæããããšã«ããããããè¡ãããšãã§ããŸãã AddInMemoryIdentityResources
ã ããã§ãªãœãŒã¹ãæå³ãããã®ãšãããããªãå¿
èŠãã«ã€ããŠèªãããšãã§ããŸã ã
Configure
æ¹æ³ã¯æ¬¡ã®ããã«ãªããŸã
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(LogLevel.Debug); app.UseDeveloperExceptionPage(); // middleware IdentityServer app.UseIdentityServer(); // 2 , app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); }
IdentityServerã® å
¬åŒã®ã¹ã¿ãŒã¿ãŒUI ãªããžããªããããŠã³ããŒããããã¡ã€ã«ããããžã§ã¯ããã©ã«ããŒã«ã³ããŒããŠããã©ã«ããŒã®æ§é ãäžèŽããããã«ããŸãïŒããšãã°ãwwwrootãšwwwrootïŒã
ãããžã§ã¯ããã³ã³ãã€ã«ãããŠããããšã確èªããŸãã
2. API
ãã®ãããžã§ã¯ãã¯ãã¢ã¯ã»ã¹ãå¶éãããããã¡ãã®APIãµãŒããŒã§ãã
å¥ã®ç©ºã®Apiãããžã§ã¯ãããœãªã¥ãŒã·ã§ã³ã«è¿œå ãããã©ãããã©ãŒã ãšããŠASP.NET Core 1.1ãéžæããŸãã ãªããªã ãã®ãããžã§ã¯ãã§ã¯æ¬æ ŒçãªWebã¢ããªã±ãŒã·ã§ã³ãäœæããã®ã§ã¯ãªããJSONãæäŸãã軜éã®WebãµãŒãã¹ã®ã¿ãäœæãããããå®å
šãªMvcã§ã¯ãªãMvcCoreããã«ãŠã§ã¢ã«å¶éããŸãã
ããã±ãŒãžãããŒãžã£ãŒã³ã³ãœãŒã«ã§ãããã®ã³ãã³ããå®è¡ããŠãå¿
èŠãªããã±ãŒãžã远å ããŸã
Install-Package Microsoft.AspNetCore.Mvc.Core -Version 1.1.3 Install-Package Microsoft.AspNetCore.Mvc.Formatters.Json -Version 1.1.3 Install-Package Microsoft.AspNetCore.Cors -Version 1.1.2 Install-Package IdentityServer4.AccessTokenValidation -Version 1.2.1
ãŸããå¿
èŠãªKestrelèšå®ãProgram.csã«è¿œå ããŸãã
public static void Main(string[] args) { Console.Title = "API"; var host = new WebHostBuilder() .UseKestrel() .UseUrls("http://localhost:5001") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); }
Startup.csã¯ããããã«å°ãªã倿Žã§æžã¿ãŸãã
ConfigureServices
public void ConfigureServices(IServiceCollection services) { services.AddCors(options=> { // CORS, API options.AddPolicy("default", policy => { policy.WithOrigins("http://localhost:5003") .AllowAnyHeader() .AllowAnyMethod(); }); }); // MVC Core Razor, DataAnnotations , Asp.NET 4.5 WebApi services.AddMvcCore() // , Authorize .AddAuthorization(options => // Roles magic strings, options.AddPolicy("AdminsOnly", policyUser => { policyUser.RequireClaim("role", "admin"); }) ) // AddMVC, AddMvcCore, JSON .AddJsonFormatters(); }
ãããŠãããã¯Configure
ããã«èŠããã¯ãã§ã
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(LogLevel.Debug); // middleware CORS app.UseCors("default"); // middleware OpenId Connect JWT- app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { // IdentityServer Authority = "http://localhost:5000", // , HTTPS IdentityServer, true // https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.builder.openidconnectoptions RequireHttpsMetadata = false, // aud access_token JWT ApiName = "api1", // , api scopes scope // AllowedScopes = { "api1.read", "api1.write" } // JWT- claims HttpContext.User Authorize , AutomaticAuthenticate = true, // middleware authentication challenge AutomaticChallenge = true, // [Authorize], IdentityServerAuthenticationOptions - RoleClaimType = "role", }); app.UseMvc(); }
ã³ã³ãããŒã©ãŒã远å ããããã«æ®ãããŠãŒã¶ãŒã®çŸåšã®ã¯ã¬ãŒã ãè¿ããŸããããã¯ãããã«ãŠã§ã¢èªèšŒIdentityServerã access_tokenã埩å·åããæ¹æ³ãçè§£ããã®ã«äŸ¿å©ã§ãã
åäžã®IdentityController
ããããžã§ã¯ãã«è¿œå ããŸãã
ãã¡ã€ã«ã®å
å®¹ã¯æ¬¡ã®ããã«ãªããŸãã
using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; namespace Api.Controllers { [Authorize] public class IdentityController : ControllerBase { [HttpGet] [Route("identity")] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } [HttpGet] [Route("superpowers")] [Authorize(Policy = "AdminsOnly")] public IActionResult Superpowers() { return new JsonResult("Superpowers!"); } } }
ãããžã§ã¯ããã³ã³ãã€ã«ãããŠããããšã確èªããŠãã ããã
3.ã¯ã©ã€ã¢ã³ã
ãã®ãããžã§ã¯ãã«ã¯ãå®éã«ã¯éèŠãªãµãŒããŒéšåã¯å«ãŸããŠããŸããã ãã¹ãŠã®ãµãŒããŒã³ãŒãã¯ãéçã¯ã©ã€ã¢ã³ããã¡ã€ã«ãæäŸããããã«ãKestrel WebãµãŒããŒã®èšå®ã«ãããŸããã
åã®2åãšåæ§ã«ã空ã®ãããžã§ã¯ãããœãªã¥ãŒã·ã§ã³ã«è¿œå ãã Clientãšããååãä»ããŸãã
éçãã¡ã€ã«ãæäœããããã®ããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãã
Install-Package Microsoft.AspNetCore.StaticFiles -Version 1.1.2
Program.csãã¡ã€ã«ã倿Žãã
public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseUrls("http://localhost:5003") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); }
Startup
ã¯ã©ã¹ã«ã¯ãã®ã³ãŒããå«ãŸããŠããå¿
èŠããããŸãã
public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app) { app.UseDefaultFiles(); app.UseStaticFiles(); }
äžæ¹ãJavaScriptã¯ã©ã€ã¢ã³ãã³ãŒãã«ã¯ããã¹ãŠã®èªèšŒããžãã¯ãšApiåŒã³åºããå«ãŸããŠããŸãã
次ã®ãã¡ã€ã«ããããžã§ã¯ãã®wwwrootãã©ã«ããŒã«1ã€ãã€è¿œå ããŸãã
index.html
ããŸããŸãªã¢ã¯ã·ã§ã³ã®ãã¿ã³ãšapp.js
ããã³oidc-client.js
ã¢ããªã±ãŒã·ã§ã³JavaScriptãã¡ã€ã«ãžã®ãªã³ã¯ãåããã·ã³ãã«ãªHTMLãã¡ã€ã«ãoidc-client.js
-OpenId Connectãå®è£
ããã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªapp.js
- oidc-clientèšå®ãšãã¿ã³ã€ãã³ããã³ãã©ãŒcallback.html
èªèšŒãµãŒããŒãã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ããªãã€ã¬ã¯ãããããŒãžããã°ã€ã³æé ãå®äºããããã«å¿
èŠãªãã©ã¡ãŒã¿ãŒãæž¡ããŸããcallback-silent.html
- callback.html
ã«äŒŒãããŒãžããã ããiframeãä»ãããããã¯ã°ã©ãŠã³ããåãã°ã€ã³ãçºçããå Žåã®ã¿ã ããã¯ã refresh_token
ã䜿çšããã«ãªãœãŒã¹ãžã®ãŠãŒã¶ãŒã¢ã¯ã»ã¹ãæ¡åŒµããããã«å¿
èŠrefresh_token
ã
index.html
ãã®ååã®æ°ããHTMLãã¡ã€ã«ããããžã§ã¯ãã®wwwrootãã©ã«ããŒã«è¿œå ããŸãã
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <button id="login">Login</button> <button id="getUser">Get User</button> <button id="getSuperpowers">Get Superpowers!</button> <button id="api">Call API</button> <button id="logout">Logout</button> <pre id="results"></pre> <script src="oidc-client.js"></script> <script src="app.js"></script> </body> </html>
oidc-client.js
ãã ïŒ1.3.0ïŒ ãããã®ãã¡ã€ã«ãããŠã³ããŒãããŠããããžã§ã¯ãã«è¿œå ããŸãã
app.js
ãã®ååã®æ°ããJavaScriptãã¡ã€ã«ããããžã§ã¯ãã®wwwrootãã©ã«ããŒã«è¿œå ããŸãã
远å ãã
/// <reference path="oidc-client.js" />
IntelliSenseãµããŒãã®ãã¡ã€ã«ã®å
é ã
ãã®ã³ãŒããapp.js
ã®äžéšã«è²Œãä»ããŸã
Oidc.Log.logger = console; Oidc.Log.level = 4;
æåã®è¡ã¯ãåŒã³åºãããã¡ãœãããšã®äºææ§ã䜿çšããŠãæšæºãã©ãŠã¶ã³ã³ãœãŒã«ãoidc-clientã®æšæºãã¬ãŒãšããŠèšå®ããŸã ã 2è¡ç®ã¯ããã¹ãŠã®ã¡ãã»ãŒãžã衚瀺ããããšã§ãã ããã«ãããèšäºã®ç¬¬2éšã«é²ã¿ãå®è£
ãã©ã®ããã«æ©èœããããèŠããšãã«ã詳现ã確èªã§ããŸãã
ããã§ã¯ããã®ãã¡ã€ã«ã«æ®ãã®éšåã®ã³ãŒãã远å ããŸãããã
ã³ãŒãã®ãã®éšåã¯æãé·ããããããæãè峿·±ããã®ã§ãã oidc-clientã©ã€ãã©ãªã®ã¡ã€ã³UserManager
ãªããžã§ã¯ãã®ã©ã€ãã©ãªèšå®ãšãã®äœæãå«ãŸããŠããŸãã èšå®èªäœãšãããã®ã³ã¡ã³ãã«ç²Ÿéããããšããå§ãããŸãã
var config = { authority: "http://localhost:5000", // IdentityServer client_id: "js", // IdentityServer // , // - OpenId Connect redirect_uri: "http://localhost:5003/callback.html", // Response Type , Authorization Endpoint // , Implicit Flow // http://openid.net/specs/openid-connect-core-1_0.html#Authentication response_type: "id_token token", // subject id , id_token, access_token api1 (. c IdentityServer) scope: "openid profile api1", // , post_logout_redirect_uri: "http://localhost:5003/index.html", // IdentityServer, true monitorSession: true, // , , 2000 checkSessionInterval: 30000, // access_token https://tools.ietf.org/html/rfc7009 revokeAccessTokenOnSignout: true, // , , 300 // https://github.com/IdentityModel/oidc-client-js/blob/1.3.0/src/JoseUtil.js#L95 clockSkew: 300, // UserInfo endpoint , loadUserInfo: true, }; var mgr = new Oidc.UserManager(config);
次ã«ããã¿ã³ã®ãã³ãã©ãŒã远å ããŠãµãã¹ã¯ã©ã€ãããŸãã
function login() { // mgr.signinRedirect(); } function displayUser() { mgr.getUser().then(function (user) { if (user) { log("User logged in", user.profile); } else { log("User not logged in"); } }); } function api() { // claims requestUrl(mgr, "http://localhost:5001/identity"); } function getSuperpowers() { // endpoint requestUrl(mgr, "http://localhost:5001/superpowers"); } function logout() { // mgr.signoutRedirect(); } document.getElementById("login").addEventListener("click", login, false); document.getElementById("api").addEventListener("click", api, false); document.getElementById("getSuperpowers").addEventListener("click", getSuperpowers, false); document.getElementById("logout").addEventListener("click", logout, false); document.getElementById("getUser").addEventListener("click", displayUser, false); // displayUser();
ããã€ãã®ãŠãŒãã£ãªãã£ã远å ããŸã
function requestUrl(mgr, url) { mgr.getUser().then(function (user) { var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = function () { log(xhr.status, 200 == xhr.status ? JSON.parse(xhr.responseText) : "An error has occured."); } // Authorization access_token Bearer - . xhr.setRequestHeader("Authorization", "Bearer " + user.access_token); xhr.send(); }); } function log() { document.getElementById('results').innerText = ''; Array.prototype.forEach.call(arguments, function (msg) { if (msg instanceof Error) { msg = "Error: " + msg.message; } else if (typeof msg !== 'string') { msg = JSON.stringify(msg, null, 2); } document.getElementById('results').innerHTML += msg + '\r\n'; }); }
ååãšããŠãããã¯çµäºããå¯èœæ§ããããŸããããã°ã€ã³æé ãå®äºããããã«å¿
èŠãªããŒãžãããã«2ã€è¿œå ããå¿
èŠããããŸãã ãã®ã³ãŒããå«ãããŒãžãwwwroot
远å ããŸãã
callback.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <script src="oidc-client.js"></script> <script> new Oidc.UserManager().signinRedirectCallback().then(function () { window.location = "index.html"; }).catch(function (e) { console.error(e); }); </script> </body> </html>
callback-silent.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <script src='oidc-client.js'></script> <script> new Oidc.UserManager().signinSilentCallback(); </script> </body> </html>
ã§ããïŒ
ä»çµã¿
次ã®ãããªãããžã§ã¯ããéå§ããããšããå§ãããŸããã³ã³ãœãŒã«ãèµ·åãããããžã§ã¯ããã©ã«ããŒã«ç§»åããŠã dotnet run
ã³ãã³ããå®è¡ããŸãã ããã«ããã IdentityServerããã³ä»ã®ã¢ããªã±ãŒã·ã§ã³ãã³ã³ãœãŒã«ã«ãã°ã€ã³ããŠããããšã確èªã§ããŸãã
æåã«IdentityServerãšApiãèµ·åããæ¬¡ã«Clientãèµ·åããŸãã
http://localhost:5003/index.html
ClientããŒãžãéããŸãã
ãã®æç¹ã§ãã³ã³ãœãŒã«ãclear()
ã§clear()
ããããšãã§ããŸãã
次ã«ãã³ã³ãœãŒã«ãèšå®ããŠããã¹ãŠã®è峿·±ãæ
å ±ãå®éã«è¡šç€ºããŸãã
ããšãã°ãChrome 60ã®å Žåãã³ã³ãœãŒã«èšå®ã¯æ¬¡ã®ããã«ãªããŸãã

éçºè
ã®ããŒã«ã®[ ãããã¯ãŒã¯ ]ã¿ãã§ã[ ãã°ã®ä¿å]ã®æšªã®ãã§ãã¯ããã¯ã¹ããªã³ã«ããŠãå°æ¥ãªãã€ã¬ã¯ããããŸããŸãªãã©ã¡ãŒã¿ãŒã®å€ã確èªããã®ã劚ããªãããã«ããããšãã§ããŸãã
CTRL + F5ã§ããŒãžãæŽæ°ããŸãã
ããããŒãã¹
仿§ã®æåã®2ã€ã®ã¹ãããã«å¯Ÿå¿ããã¢ã¯ã·ã§ã³ãèŠãŠã¿ãŸãããã
1. ã¯ã©ã€ã¢ã³ãã¯ãå¿
èŠãªèŠæ±ãã©ã¡ãŒã¿ãŒãå«ãèªèšŒèŠæ±ãæºåããŸãã
2. ã¯ã©ã€ã¢ã³ã㯠ãèªèšŒ ãµãŒããŒã« èªèšŒèŠæ±ãéä¿¡ã ãŸã ã
[ãã°ã€ã³]ãã¿ã³ãã¯ãªãã¯ããŸãã
èš±å¯ãµãŒããŒãšã®å¯Ÿè©±ã¯ãã¢ãã¬ã¹ãžã®GETèŠæ±ã§å§ãŸããŸã
http://localhost:5000/.well-known/openid-configuration
ãã®ãªã¯ãšã¹ãã«ããã oidc-clientã¯ãOpenId Connectãããã€ããŒã®ã¡ã¿ããŒã¿ãåãåããŸãïŒãã®ã¢ãã¬ã¹ãå¥ã®ã¿ãã§éãããšããå§ãããŸãïŒãããã«ã¯authorization_endpoint
å«ãŸauthorization_endpoint
http://localhost:5000/connect/authorize
WebStorageã¯ãŠãŒã¶ãŒæ
å ±ã®ä¿åã«äœ¿çšãããããšã«æ³šæããŠãã ããã oidc-clientã䜿çšãããšã䜿çšãããªããžã§ã¯ããæå®ã§ããŸããããã©ã«ãã§ã¯sessionStorage
ã§ãã
ãã®æç¹ã§ãèªèšŒãªã¯ãšã¹ãã¯ãããã®ã¯ãšãªæååãã©ã¡ãŒã¿ãŒãšãšãã«authorization_endpoint
ã«éä¿¡ãauthorization_endpoint
ãŸã
redirect_uriã¯ã IdentityServerèšå®ã§client_id
jsã䜿çšããŠã¯ã©ã€ã¢ã³ãã«æå®ããã¢ãã¬ã¹ã«å¯Ÿå¿ããããšã«æ³šæããŠãã ããã
ãªããªã ãŠãŒã¶ãŒããŸã èªèšŒãããŠããªãå Žåã IdentityServer㯠ãã°ã€ã³ãã©ãŒã ãžã®ãªãã€ã¬ã¯ããåçãšããŠéä¿¡ããŸãã
次ã«ããã©ãŠã¶ãŒã¯http://localhost:5000/account/login
ãªãã€ã¬ã¯ãããhttp://localhost:5000/account/login
ã
3. èªèšŒãµãŒããŒã¯ãšã³ããŠãŒã¶ãŒãèªèšŒããŸã ã
4. æ¿èªãµãŒããŒã¯ã ãšã³ããŠãŒã¶ãŒãã確èªãåãåããŸã ã
5. èªå¯ãµãŒããŒã¯ ãIDããŒã¯ã³ãšãå¿
èŠã«å¿ããŠã¢ã¯ã»ã¹ããŒã¯ã³ãšãšãã«ãšã³ããŠãŒã¶ãŒãã¯ã©ã€ã¢ã³ãã«éãè¿ããŸãã
ãã°ã€ã³ãšããŠbobãã ãã¹ã¯ãŒããšããŠpasswordãå
¥åããŠããã©ãŒã ãéä¿¡ããŸãã
æåã«authorization_endpoint
ã«ãªãã€ã¬ã¯ããauthorization_endpoint
ãããããããŸããŸãªã¹ã³ãŒããžã®èšŒææžå©çšè
ïŒãã®å Žåã¯js-clientïŒã¢ã¯ã»ã¹ãåä¿¡ããããã®OpenId Connectèš±å¯ã«åŸã£ãŠç¢ºèªããŒãžã«ãªãã€ã¬ã¯ããããŸãã
ãã¹ãŠã«åæãããã©ãŒã ãéä¿¡ããŸãã èªèšŒãã©ãŒã ãšåæ§ã«ããã©ãŒã ã®éä¿¡ã«å¿ããŠauthorization_endpoint
ã«ãªãã€ã¬ã¯ããauthorization_endpoint
ã authorization_endpoint
ããŒã¿ã¯Cookieã䜿çšããŠéä¿¡ãããŸãã
ããããããã©ãŠã¶ã¯å
ã®èªèšŒèŠæ±ã§redirect_uri
ãšããŠæå®ãããã¢ãã¬ã¹ã«redirect_uri
ããŸãã
æé»ãããŒã䜿çšããå Žåã #
ãŸãã ããã¯ããããã®å€ãJavaScriptã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšã§ããããã«ããããã«å¿
èŠã§ãããWebãµãŒããŒã«ã¯éä¿¡ãããŸããã
å | äŸ¡å€ |
---|
id_token | ã¯ã©ã€ã¢ã³ãã®ãŠãŒã¶ãŒããŒã¿ãå«ãããŒã¯ã³ |
access_token | APIãžã®ã¢ã¯ã»ã¹ã«å¿
èŠãªããŒã¿ãå«ãããŒã¯ã³ |
token_type | access_token ãšå
¥åããŸãããã®å Žåã¯Bearer |
expires_in | access_token ã¢ã¯ã·ã§ã³access_token |
ç¯å² | scopes |
6. id token Subject Identifier .
oidc-client state, nonce id_token
. , (, sub
claim id_token
). id_token
oidc-client .
id_token
( Network ), , payload -
{ "nbf": 1505143180, "exp": 1505146780, "iss": "http://localhost:5000", "aud": "js", "nonce": "2bd3ed0b260e407e8edd0d03a32f150c", "iat": 1505143180, "at_hash": "UAeZEg7xr23ToH2R2aUGOA", "sid": "053b5d83fd8d3ce3b13d3b175d5317f2", "sub": "2", "auth_time": 1505143180, "idp": "local", "name": "Bob", "website": "https://bob.com", "amr": [ "pwd" ] }
at_hash
, .
access_token
payload , , .
{ "nbf": 1505143180, "exp": 1505143480, "iss": "http://localhost:5000", "aud": [ "http://localhost:5000/resources", "api1" ], "client_id": "js", "sub": "2", "auth_time": 1505143180, "idp": "local", "name": "Bob", "role": "admin", "scope": [ "openid", "profile", "api1" ], "amr": [ "pwd" ] }
, â . , IdentityServer .
, claims id_token
.
, loadUserInfo
, UserInfo Endpoint . UserInfo Endpoint claims Authorization Bearer - access_token
, claims JavaScript- .
loadUserInfo
access_token
, HTTP-, .
API
"Call API".
ajax- http://localhost:5001/identity
.
, OPTIONS- CORS .. , "" ( Authorization
, ).
, , GET -. , Authorization Bearer < access_token> .
IdentityServer middleware . IdentityServer middleware Asp.Net Core JwtBearerMiddleware .
, 200.
Logout
GET- end_session_endpoint
| |
---|
id_token_hint | id_token |
post_logout_redirect_uri | URI, , |
, .
, . , - , - .
alice Get Superpowers! , bob .
do not allow
Logout ,
Username: alice
Password: password
http://localhost:5000/consent
No, Do Not Allow .
http://localhost:5003/callback.html
.
, URL #error=access_denied
, signinRedirectCallback
, rejected .
callback.html
catch-, .
id_token
URL , claims, scope profile.
Claims, scope profile .
API .
api1
claim api1
"scope": [ "openid", "profile" ],
Api 401 (Unathorized).
access_token
access_token
, Call API .
API ! , IdentityServer middleware Asp.Net Core, ClockSkew. , , , , . ClockSkew 5 .
5 , API 401 (Unathorized).
401, access_token
.
access_token
app.js
config
,
var config = { // ... // true, access_token , false automaticSilentRenew: true, // "" iframe silent_redirect_uri: 'http://localhost:5003/callback-silent.html', // oidc-client access_token accessTokenExpiringNotificationTime: 60, // ... }
access_token
. Call API , .
id_token
access_token
API , , , id_token
. js-. .
ãããã«
, :
- OpenId Connect Implicit Flow IdentityServer oidc-client ASP.NET Core 1.1.
- , .
- , , , , , .
䟿å©ãªãªã³ã¯
- .
- IdentityServer4
- oidc-client .
- ASP.NET Core. .
- Authorize IdentityServer.
- OpenId Connect 2 â
id_token
access_token
. - OpenId Connect ASP.NET Core.