ASP.NET Core的身份认证框架IdentityServer4--(5)自定义用户登录(使用官网提供的UI)
IdentityServer官方提供web页面,可以根据需求修改样式。具体UI下载跟配置参考官网文档。
文档地址:https://identityserver4.readthedocs.io/en/release/quickstarts/3_interactive_login.html
使用UI登录涉及的知识点参考园里大佬@solenovex的文章。这里不在重复说明,感兴趣的同学可以去看看。原文地址:https://www.cnblogs.com/cgzl/p/9253667.html
我这里是根据官方提供的UI进行修改、自定义用户登录、访问API。
源码地址:https://github.com/YANGKANG01/IdentityServer4-IdentityAuth
一、配置IdentityServer
1、引入官网包:IdentityServer4
2、需要重新定义Web端信息,除了ClientId,AllowedGrantTypes,ClientSecrets,AllowedScopes
等属性还需要配置登录成功或注销后的返回地址RedirectUris
跟PostLogoutRedirectUris
。Config
文件配置如下:
using IdentityServer4; using IdentityServer4.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace IdentityServer { /// <summary> /// IdentityServer配置 /// </summary> public class Config { /// <summary> /// 添加对OpenID Connect的支持 /// </summary> /// <returns></returns> public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), //必须要添加,否则报无效的scope错误 new IdentityResources.Profile() }; } /// <summary> /// 定义系统中的API资源 /// </summary> /// <returns></returns> public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("api1", "My API") }; } /// <summary> /// 客户端访问资源 /// </summary> /// <returns></returns> public static IEnumerable<Client> GetClients() { // 客户端信息 return new List<Client> { //自定义接口登录的客户端 new Client { //客户端ID名称 ClientId = "client1", //客户端访问方式:密码验证 AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, //用于认证的密码加密方式 ClientSecrets = { new Secret("secret".Sha256()) }, //客户端有权访问的范围 AllowedScopes = { "api1", IdentityServerConstants.StandardScopes.OpenId, //必须要添加,否则报403 forbidden错误 IdentityServerConstants.StandardScopes.Profile } }, //定义mvc客户端 new Client { //客户端ID名称 ClientId = "mvc", ClientName = "MVC Client", //访问类型 AllowedGrantTypes = GrantTypes.Hybrid, //关闭确认是否返回身份信息界面 RequireConsent=false, // 登录成功后重定向地址 RedirectUris = { "http://localhost:5002/signin-oidc" }, //注销成功后的重定向地址 PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" }, //用于认证的密码加密方式 ClientSecrets = { new Secret("secret".Sha256()) }, //客户端有权访问的范围 AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api1",//要访问的api名称 }, } }; } } }
3、Startup的配置跟前面自定义接口登录一样没什么变化,这里也贴下源码方便没看前篇的同学:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using IdentityServer.Service; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace IdentityServer { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { //配置身份服务器与内存中的存储,密钥,客户端和资源 services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(Config.GetIdentityResources())//用户信息建模 .AddInMemoryApiResources(Config.GetApiResources())//添加api资源 .AddInMemoryClients(Config.GetClients())//添加客户端 .AddResourceOwnerValidator<LoginValidator>()//用户校验 .AddProfileService<ProfileService>(); //注册mvc服务 services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //添加到HTTP管道中。 app.UseIdentityServer(); //添加静态资源访问 app.UseStaticFiles(); //添加mvc到管道中 app.UseMvcWithDefaultRoute(); } } }
4、添加官网UI后找到AccountController
类,修改登录方法Login
,把下图中的代码替换成自己的查询数据库用户即可,这里官方使用的是TestUsers
类中自定义的用户来登录。
二、Web端配置获取登录后的用户信息
1、引入官网包:IdentityModel
。
2、Startup配置如下。ResponseType
返回类型详情可参考@solenovex的文章,大佬在文章说的比较详细,这里不在重复说明,地址:https://www.cnblogs.com/cgzl/p/9253667.html
using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace Web { 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.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; //授权端服务地址 options.Authority = "http://localhost:5000/"; //是否https请求 options.RequireHttpsMetadata = false; //客户端ID名称 options.ClientId = "mvc"; options.ClientSecret = "secret"; //返回的类型 options.ResponseType = "code id_token"; //添加自定义用户信息 options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); //是否存储token options.SaveTokens = true; //用于设置在从令牌端点接收的id_token创建标识后,处理程序是否应转到用户信息端点 options.GetClaimsFromUserInfoEndpoint = true; //访问名称api options.Scope.Add("api1"); //避免claims被默认过滤掉,如果不想让中间件过滤掉nbf和amr, 把nbf和amr从被过滤掉集合里移除。可以使用下面这个方方式: options.ClaimActions.Remove("nbf"); options.ClaimActions.Remove("amr"); //删除某些Claims options.ClaimActions.DeleteClaim("sid"); options.ClaimActions.DeleteClaim("idp"); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseCookiePolicy(); //添加用户验证中间件 app.UseAuthentication(); // app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
3、在需要登录的页面方法添加Authorize
特性。
启动web 会看到页面自动重定向到登录页面效果如图:
4、获取用户信息可使用HttpContext.User.Identity
来获取当前用户信息,代码如下:
//获取用户信息 var claimIdentity = (ClaimsIdentity)HttpContext.User.Identity; var claimsPrincipal = claimIdentity.Claims as List<Claim>;
5、获取用户token
,这里的token
是服务端生成发送给客户端,用于身份校验,可使用token
访问需要登录权限的API接口。代码如下:
//获取用户token var token = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
Ps:注销登录默认跳转到退出信息提示页面,如不需要修改服务端的 AccountOptions
类中的AutomaticRedirectAfterSignOut
属性,默认为false
,修改为true
即可。
三、API配置
1、引入官网包:IdentityServer4.AccessTokenValidation
。
2、Startup类配置如下:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace API { 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.AddMvcCore() .AddAuthorization()//添加身份验证服务 .AddJsonFormatters(); //AddAuthentication将身份验证服务添加到DI并配置"Bearer"为默认方案 services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = "http://localhost:5000";//identifyServer服务地址 options.RequireHttpsMetadata = false;//是否使用https options.ApiName = "api1";//进行身份验证的API资源的名称 }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //将身份验证中间件添加到管道中 app.UseAuthentication(); app.UseMvc(); } } }
3、给对应的API接口添加Authorize
特性,Web端登录通过token
访问该接口。代码如下:
//获取用户token var token = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); //实例化HttpClient var client = new HttpClient(); client.SetBearerToken(token); //请求identity接口 var response = await client.GetAsync("http://localhost:5001/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); }