IdentityServer4 使用Authorization Code Flow保护ASP.NET Core MVC客户端
1.Authorization Code基本概念
Authorization Code
OAuth2.0 - Authorization Code Grant(授权码授权)
OpenId Connect - Authorization Code Flow(授权码流程)
使用于保密客户端(Confidential Client)
服务器端的Web应用
对用户和客户端进行身份验证
OAuth2.0 Authorization Code Grant
请求流程
身份认证请求
身份认证请求的响应
Token请求
Token请求的响应
2.ASP.NET Core MVC 客户端认证
2.1创建ASP.NET Core MVC 客户端
2.2在Startup中修改认证
这里只在Privacy页面标签进行验证
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); JwtSecurityTokenHandler.DefaultMapInboundClaims = false; //dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;//"Cookie" options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;//"oidc"; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = "https://localhost:5001"; options.RequireHttpsMetadata = false; options.ClientId = "mvc client"; options.ClientSecret = "mvc secret"; options.ResponseType = "code"; options.SaveTokens = true; options.Scope.Clear(); options.Scope.Add("scope1"); options.Scope.Add(OidcConstants.StandardScopes.OpenId); options.Scope.Add(OidcConstants.StandardScopes.Profile); options.Scope.Add(OidcConstants.StandardScopes.OfflineAccess); options.Scope.Add(OidcConstants.StandardScopes.Email); options.Scope.Add(OidcConstants.StandardScopes.Phone); options.Scope.Add(OidcConstants.StandardScopes.Address); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { //endpoints.MapDefaultControllerRoute() // .RequireAuthorization(); endpoints.MapDefaultControllerRoute(); }); //if (env.IsDevelopment()) //{ // app.UseDeveloperExceptionPage(); //} //else //{ // app.UseExceptionHandler("/Home/Error"); //} //app.UseAuthentication(); //app.UseStaticFiles(); //app.UseCookiePolicy(); //app.UseMvc(routes => //{ // routes.MapRoute( // name: "default", // template: "{controller=Home}/{action=Index}/{id?}"); //}); } }
修改认证地址及需要访问的被保护资源
2.3修改HomeController代码 获取Access Token
//[Authorize] public class HomeController : Controller { private readonly ILogger_logger; public HomeController(ILogger logger) { _logger = logger; } /// /// 使用AccessToken访问Api资源 /// /// /// public async Task Index() { //// discovery endpoint //var client = new HttpClient(); //var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001"); //if (disco.IsError) //{ // throw new Exception(disco.Error); //} //var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); //client.SetBearerToken(accessToken); //var response = await client.GetAsync("https://localhost:6001/identity"); //if (!response.IsSuccessStatusCode) //{ // throw new Exception(response.ReasonPhrase); //} //var content = await response.Content.ReadAsStringAsync(); //return View("Index", content); return View(); } [Authorize] public async Task Privacy() { var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); var idToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken); var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken); var code = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.Code); ViewData["accessToken"] = accessToken; ViewData["idToken"] = idToken; ViewData["refreshToken"] = refreshToken; return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } public async Task Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); } }
3修改Idp认证服务的配置
3.1增加Mvc客户端
public static class Config { public static IEnumerableIdentityResources => new IdentityResource[] { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email(), new IdentityResources.Phone(), new IdentityResources.Address(), }; public static IEnumerable ApiScopes => new ApiScope[] { new ApiScope("scope1"), new ApiScope("scope2"), }; public static IEnumerable Clients => new Client[] { //client credentials flow client new Client(){ ClientId = "console client", ClientName = "Client Credentials Client", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) }, AllowedScopes ={ "scope1 openid profile"} }, //wpf client password grant new Client(){ ClientId = "wpf client", ClientName = "ResourceOwnerPassword Client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("wpf secret".Sha256()) }, //允许请求api资源 APIs //允许请求身份认证的数据 identiy data AllowedScopes ={ "scope1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Phone, IdentityServerConstants.StandardScopes.Address }, }, //mvc client password grant new Client(){ ClientId = "mvc client", ClientName = "CodeAndClientCredentials Client", AllowedGrantTypes = GrantTypes.CodeAndClientCredentials, ClientSecrets = { new Secret("mvc secret".Sha256()) }, RedirectUris = { "https://localhost:5003/signin-oidc" }, FrontChannelLogoutUri = "https://localhost:5003/signin-oidc", // where to redirect to after logout PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc" }, //请求配置的Identity资源 AlwaysIncludeUserClaimsInIdToken=true, //允许refreshtoken AllowOfflineAccess = true, //允许请求api资源 APIs //允许请求身份认证的数据 identiy data AllowedScopes ={ "scope1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Phone, IdentityServerConstants.StandardScopes.Address }, } #region // // m2m client credentials flow client //new Client //{ // ClientId = "m2m.client", // ClientName = "Client Credentials Client", // AllowedGrantTypes = GrantTypes.ClientCredentials, // ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) }, // AllowedScopes = { "scope1" } //}, //// interactive client using code flow + pkce //new Client //{ // ClientId = "interactive", // ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) }, // AllowedGrantTypes = GrantTypes.Code, // RedirectUris = { "https://localhost:44300/signin-oidc" }, // FrontChannelLogoutUri = "https://localhost:44300/signout-oidc", // PostLogoutRedirectUris = { "https://localhost:44300/signout-callback-oidc" }, // AllowOfflineAccess = true, // AllowedScopes = { "openid", "profile", "scope2" } //}, #endregion }; }
3.2退出登录后跳到主页面(Home/Index)
在Account/AccountOptions下
这里我进行修改了但是登出后没有跳到Home/Index,暂时未找到原因
4.运行
4.1运行认证服务idp和被保护的资源Scope1Resource
把之前的idp和Scope1Resource都运行起来
直接在项目根目录运行bin/debug/exe文件即可
4.2运行MvcClient
4.3登录
点击Privacy直接跳到了identityserver登录界面
4.4登录成功
登录成功后idp认证资源和受保护的资源都可以进行访问
4.3登出
登录后没有跳转到Home/Index,后面学习深入后再想办法解决
5.为MVC客户端刷新Token