public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddIdentityServer() .AddSigningCredential(InMemoryConfiguration.GetX509Certificate2()) .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources) .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources) .AddInMemoryClients(InMemoryConfiguration.GetApiClients) .AddTestUsers(InMemoryConfiguration.GetApiUsers); services.AddCors(o => o.AddPolicy("CorsPolicy", b => { b.WithOrigins(Environment.GetEnvironmentVariable("CLIENT_URL").Split(",")) .AllowAnyMethod() .AllowAnyHeader(); })); services.AddMvcCore(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0); }
public void GivenDehydratedBugsResponse_WhenAskingToCreate_ThenItShouldReturnDehydratedObject() { // arrange const string bugsJson = "{}"; IConfiguration configuration = new InMemoryConfiguration().Instance(); IHttpService vstsHttpService = new VstsHttpService(new Uri(configuration["VstsApi:BaseUrl"]), new FakeHttpMessageHandler(bugsJson, new Uri(new Uri(configuration["VstsApi:BaseUrl"]), "/Strickland/_apis/wit/wiql?$top=10000&api-version=5.0-preview.2"), configuration["VstsApi:PAT"])); new Privateer().SetStaticField <VstsHttpService, HttpClient>((VstsHttpService)vstsHttpService, "_httpClient", null); IBugsFactory bugsFactory = new BugsFactory(vstsHttpService, configuration); // act Bugs bugs = bugsFactory.Create("Strickland").Result; // assert JObject jObject = JObject.Parse(JsonConvert.SerializeObject(bugs)); JToken jBugs = jObject["bugs"]; jBugs.Should().HaveCount(0); }
public void MigrateInMemoryDataToSqlServer(IApplicationBuilder app) { using (var scope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope()) { scope.ServiceProvider.GetRequiredService <PersistedGrantDbContext>().Database.Migrate(); var context = scope.ServiceProvider.GetRequiredService <ConfigurationDbContext>(); context.Database.Migrate(); if (!context.Clients.Any()) { foreach (var client in InMemoryConfiguration.Clients()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { foreach (var resource in InMemoryConfiguration.IdentityResources()) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { foreach (var resource in InMemoryConfiguration.ApiResources()) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } } }
public void ConfigureServices(IServiceCollection services) { //my user repository services.AddScoped <IUserRepository, UserRepository>(); services.AddIdentityServer() .AddDeveloperSigningCredential() // .AddSigningCredential(new X509Certificate2(@"/etc/nginx/ssl/socialnetwork.pfx", "2wsx3edc")) //.AddSigningCredential(new X509Certificate2(@"/Users/jiangzhimin/socialnetwork.pfx", "2wsx3edc")) // .AddSigningCredential(new X509Certificate2(LocaPath + "/Pfx/socialnetwork.pfx", "2wsx3edc")) // .AddTestUsers(InMemoryConfiguration.Users().ToList()) .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryClients(InMemoryConfiguration.Clients()) .AddInMemoryApiResources(InMemoryConfiguration.ApiResources()) .AddProfileService <ProfileService>(); //Inject the classes we just created services.AddTransient <IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>(); services.AddTransient <IProfileService, ProfileService>();//再做一次 像new }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton(new GetTableData(Environment.ContentRootPath)); services.AddSingleton(new Appsettings(Environment.ContentRootPath)); services.AddSingleton <IUserService, UserService>(); services.AddSingleton <IRoleService, RoleService>(); services.AddSingleton <IUserRoleService, UserRoleService>(); #region ²âÊÔIdentityServer4 var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }) // in-memory, code config .AddTestUsers(InMemoryConfiguration.Users().ToList()) .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()); //.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>() //.AddProfileService<CustomProfileService>(); builder.AddDeveloperSigningCredential(); if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); } #endregion services.AddRazorPages(); }
private void InitializeDatabase(IApplicationBuilder app) { using (var serviceScope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope()) { serviceScope.ServiceProvider.GetRequiredService <PersistedGrantCustomDbContext>().Database.Migrate(); var context = serviceScope.ServiceProvider.GetRequiredService <ConfigurationCustomDbContext>(); var appDbContext = serviceScope.ServiceProvider.GetRequiredService <ApplicationDbContext>(); context.Database.Migrate(); appDbContext.Database.Migrate(); if (!context.Clients.Any()) { foreach (var client in InMemoryConfiguration.Clients()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { foreach (var resource in InMemoryConfiguration.GetIdentityResources()) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { foreach (var resource in InMemoryConfiguration.ApiResources()) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } } }
public void GivenDehydratedProjectsResponse_WhenAskingToCreate_ShouldReturnDehydratedObject() { // arrange const string projectsJson = "{}"; IConfiguration configuration = new InMemoryConfiguration().Instance(); IHttpService vstsHttpService = new VstsHttpService(new Uri(configuration["VstsApi:BaseUrl"]), new FakeHttpMessageHandler(projectsJson, new Uri(new Uri(configuration["VstsApi:BaseUrl"]), "/_apis/projects?api-version=4.1-preview.1"), configuration["VstsApi:PAT"])); new Privateer().SetStaticField <VstsHttpService, HttpClient>((VstsHttpService)vstsHttpService, "_httpClient", null); IProjectsFactory projectsFactory = new ProjectsFactory(vstsHttpService, configuration); // act Projects projects = projectsFactory.Create(); // assert JObject jObject = JObject.Parse(JsonConvert.SerializeObject(projects)); jObject.Value <int>("count").Should().Be(0); JToken jProjects = jObject["projects"]; jProjects.Should().HaveCount(0); }
/// <summary> /// InitializeIdentityServerDatabase /// </summary> /// <param name="app">IApplicationBuilder</param> /// <returns></returns> private async Task InitializeDatabase(IApplicationBuilder app) { using (var serviceScope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope()) { var context = serviceScope.ServiceProvider.GetService <IConfigurationDbContext>(); if (!context.Clients.Any()) { foreach (var client in InMemoryConfiguration.Clients()) { await context.AddClient(client.ToEntity()); } } if (!context.ApiResources.Any()) { foreach (var resource in InMemoryConfiguration.ApiResources()) { await context.AddApiResource(resource.ToEntity()); } } if (!context.IdentityResources.Any()) { foreach (var identity in InMemoryConfiguration.IdentityResources()) { await context.AddIdentityResource(identity.ToEntity()); } } var repo = serviceScope.ServiceProvider.GetService <IUserRepository>(); if (!repo.FindAll().Any()) { var user = new User { UserName = "******", Password = "******", }; repo.Insert(user); } } }
public void ConfigureServices(IServiceCollection services) { services.AddIdentityServer() .AddSigningCredential(new X509Certificate2(@"C:\dev\todoResources.pfx", "")) .AddTestUsers(InMemoryConfiguration.Users().ToList()) .AddInMemoryClients(InMemoryConfiguration.Clients()) .AddInMemoryApiResources(InMemoryConfiguration.ApiResources()); services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.SaveToken = true; options.ApiName = "todoResources"; options.ApiSecret = "SKB Kontur"; }); services.AddScoped <ToDoService>(); services.AddMvc(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDbContext <ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity <ApplicationUser, IdentityRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders(); // Add application services. services.AddTransient <IEmailSender, EmailSender>(); services.AddMvc(); services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryPersistedGrants() .AddInMemoryIdentityResources(InMemoryConfiguration.IdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.ApiResources()) .AddInMemoryClients(InMemoryConfiguration.Clients()) //.AddAspNetIdentity<ApplicationUser>(); .AddTestUsers(Users.All()); }
public void GivenBugData_WhenAskingToCreate_ThenItShouldReturnBugs() { // arrange string bugsJson = new TestData().Bugs(); IConfiguration configuration = new InMemoryConfiguration().Instance(); IHttpService vstsHttpService = new VstsHttpService(new Uri(configuration["VstsApi:BaseUrl"]), new FakeHttpMessageHandler(bugsJson, new Uri(new Uri(configuration["VstsApi:BaseUrl"]), "/Strickland/_apis/wit/wiql?$top=10000&api-version=5.0-preview.2"), configuration["VstsApi:PAT"])); new Privateer().SetStaticField <VstsHttpService, HttpClient>((VstsHttpService)vstsHttpService, "_httpClient", null); IBugsFactory bugsFactory = new BugsFactory(vstsHttpService, configuration); // act Bugs bugs = bugsFactory.Create("Strickland").Result; // assert JObject jObject = JObject.Parse(JsonConvert.SerializeObject(bugs)); JToken jBugs = jObject["bugs"]; jBugs.Should().HaveCount(11); jBugs[0].Value <int>("id").Should().Be(777); jBugs[0].Value <string>("url").Should().Be("https://premeraservices.visualstudio.com/d30fd324-c3ab-4edc-ac5d-ba4514ba5ec4/_apis/wit/workItems/777"); }
public async Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { return(await Task.Run(() => { var client = InMemoryConfiguration.Clients().FirstOrDefault(s => s.ClientId == parsedSecret.Id); if (client != null) { foreach (var item in client.ClientSecrets) { //验证逻辑 自定义 if (item.Value == parsedSecret.Credential.ToString()) { return new SecretValidationResult { Success = true }; } } // client.ClientSecrets == parsedSecret.Credential; } return new SecretValidationResult { Success = false }; })); }
public void TestInitialize() { //Setup connection per tests database = new DatabaseContext(InMemoryConfiguration.Configure()); users = new UserApi(database); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { #region IdentityServer4+FreeSql InMemoryConfiguration.Configuration = this.Configuration; services.AddSingleton(Fsql); services.AddFreeRepository(filter => { filter.Apply <ISoftDeleteAduitEntity>("SoftDelete", a => a.IsDeleted == false); }, GetType().Assembly, typeof(AuditBaseRepository <>).Assembly); services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.GetApis()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddProfileService <LinCmsProfileService>() .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>(); #region AddAuthentication\AddIdentityServerAuthentication //AddAuthentication()是把验证服务注册到DI, 并配置了Bearer作为默认模式. //AddIdentityServerAuthentication()是在DI注册了token验证的处理者. //由于是本地运行, 所以就不使用https了, RequireHttpsMetadata = false.如果是生产环境, 一定要使用https. //Authority指定Authorization Server的地址. //ApiName要和Authorization Server里面配置ApiResource的name一样. //和 AddJwtBearer不能同时使用,目前还不理解区别。 //services // .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme) // .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options => // { // options.RequireHttpsMetadata = false; // for dev env // options.Authority = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}"; ; // options.ApiName = Configuration["Service:Name"]; // match with configuration in IdentityServer // options.JwtValidationClockSkew = TimeSpan.FromSeconds(60*5); // }); #endregion #region AddJwtBearer services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { //identityserver4 地址 也就是本项目地址 options.Authority = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}"; options.RequireHttpsMetadata = false; options.Audience = Configuration["Service:Name"]; //options.TokenValidationParameters = new TokenValidationParameters() //{ // ClockSkew = TimeSpan.Zero //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟 //}; //使用Authorize设置为需要登录时,返回json格式数据。 options.Events = new JwtBearerEvents() { OnChallenge = context => { //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦 context.HandleResponse(); string msg; ErrorCode errorCode; int statusCode = StatusCodes.Status401Unauthorized; if (context.Error == "invalid_token" && context.ErrorDescription == "The token is expired") { msg = "令牌过期"; errorCode = ErrorCode.TokenExpired; statusCode = StatusCodes.Status422UnprocessableEntity; } else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty()) { msg = "令牌失效"; errorCode = ErrorCode.TokenInvalidation; } else { msg = "认证失败,请检查请求头或者重新登陆"; errorCode = ErrorCode.TokenInvalidation; } context.Response.ContentType = "application/json"; context.Response.StatusCode = statusCode; context.Response.WriteAsync(new ResultDto(errorCode, msg, context.HttpContext).ToString()); return(Task.FromResult(0)); } }; }); #endregion #endregion services.AddAutoMapper(typeof(Startup).Assembly, typeof(PoemProfile).Assembly); services.AddCors(option => option.AddPolicy("cors", policy => policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().AllowAnyOrigin())); #region Mvc services.AddMvc(options => { options.ValueProviderFactories.Add(new SnakeCaseQueryValueProviderFactory()); //设置SnakeCase形式的QueryString参数 options.Filters.Add <LinCmsExceptionFilter>(); options.Filters.Add <LogActionFilterAttribute>(); // 添加请求方法时的日志记录过滤器 }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true; //自定义 BadRequest 响应 options.InvalidModelStateResponseFactory = context => { var problemDetails = new ValidationProblemDetails(context.ModelState); var resultDto = new ResultDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext); return(new BadRequestObjectResult(resultDto) { ContentTypes = { "application/json" } }); }; }) .AddJsonOptions(opt => { //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss"; //设置时间戳格式 opt.SerializerSettings.Converters = new List <JsonConverter>() { new LinCmsTimeConverter() }; // 设置下划线方式,首字母是小写 opt.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new SnakeCaseNamingStrategy() { ProcessDictionaryKeys = true } }; }); #endregion services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); #region Scrutor 与单个单个注册等价,不过可批量注册 //services.AddScoped<ILogService, LogService>(); //services.AddScoped<IUserSevice, UserService>(); services.Scan(scan => scan //加载Startup这个类所在的程序集 .FromAssemblyOf <Startup>() // 表示要注册那些类,上面的代码还做了过滤,只留下了以 Service 结尾的类 .AddClasses(classes => classes.Where(t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))) //表示将类型注册为提供其所有公共接口作为服务 .AsImplementedInterfaces() //表示注册的生命周期为 Transient .WithTransientLifetime() // We start out with all types in the assembly of ITransientService .FromAssemblyOf <IScopeDependency>() // AddClasses starts out with all public, non-abstract types in this assembly. // These types are then filtered by the delegate passed to the method. // In this case, we filter out only the classes that are assignable to ITransientService. .AddClasses(classes => classes.AssignableTo <ITransientDependency>()) // We then specify what type we want to register these classes as. // In this case, we want to register the types as all of its implemented interfaces. // So if a type implements 3 interfaces; A, B, C, we'd end up with three separate registrations. .AsImplementedInterfaces() // And lastly, we specify the lifetime of these registrations. .WithTransientLifetime() ); #endregion #region Swagger //Swagger重写PascalCase,改成SnakeCase模式 services.TryAddEnumerable(ServiceDescriptor .Transient <IApiDescriptionProvider, SnakeCaseQueryParametersApiDescriptionProvider>()); //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Info() { Title = "LinCms", Version = "v1" }); var security = new Dictionary <string, IEnumerable <string> > { { "Bearer", new string[] { } }, }; options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition("Bearer", new ApiKeyScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = "header", //jwt默认存放Authorization信息的位置(请求头中) Type = "apiKey" }); string basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径) string xmlPath = Path.Combine(basePath, "LinCms.Web.xml"); options.IncludeXmlComments(xmlPath); options.OperationFilter <SwaggerFileHeaderParameter>(); }); #endregion //将Handler注册到DI系统中 services.AddScoped <IAuthorizationHandler, PermissionAuthorizationHandler>(); services.Configure <FormOptions>(options => { options.MultipartBodyLengthLimit = 1024 * 1024 * 2; options.MultipartHeadersCountLimit = 10; }); }
protected override void CustomSetUp() { base.CustomSetUp(); _config = new InMemoryConfiguration(Guid.NewGuid().ToString()); }
public void Init() { var config = new InMemoryConfiguration("borkbork"); realm = Realm.GetInstance(config); }
public void ConfigureServices(IServiceCollection services) { InMemoryConfiguration.Configuration = this.Configuration; services.AddContext(); services.AddCors(); services.AddHash(); services.AddCryptography("lin-cms-dotnetcore-cryptography"); services.ConfigureApplicationCookie(options => { options.LoginPath = "/account/login"; }); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(120); }); services.AddIdentityServer(options => new IdentityServerOptions { UserInteraction = new UserInteractionOptions { LoginUrl = "/account/login", LogoutUrl = "/account/logout", } }) #if DEBUG .AddDeveloperSigningCredential() #endif #if !DEBUG .AddSigningCredential(new X509Certificate2( Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]), Configuration["Certificates:Password"]) ) #endif .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.GetApis()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddInMemoryApiScopes(InMemoryConfiguration.GetApiScopes()) .AddProfileService <LinCmsProfileService>() .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>(); #region Swagger //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { string ApiName = "LinCms.IdentityServer4"; options.SwaggerDoc("v1", new OpenApiInfo() { Title = ApiName + RuntimeInformation.FrameworkDescription, Version = "v1", Contact = new OpenApiContact { Name = ApiName, Email = "*****@*****.**", Url = new Uri("https://www.cnblogs.com/igeekfan/") }, License = new OpenApiLicense { Name = ApiName + " 官方文档", Url = new Uri("https://luoyunchong.github.io/vovo-docs/dotnetcore/lin-cms/dotnetcore-start.html") } }); var security = new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Id = "Bearer", Type = ReferenceType.SecurityScheme } }, Array.Empty <string>() } }; options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); try { string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlPath, true); } catch (Exception ex) { Log.Logger.Warning(ex.Message); } options.AddServer(new OpenApiServer() { Url = "", Description = "vvv" }); options.CustomOperationIds(apiDesc => { var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor; return(controllerAction.ControllerName + "-" + controllerAction.ActionName); }); }); #endregion services.AddTransient <IUserRepository, UserRepository>(); services.AddTransient <IUserIdentityService, UserIdentityService>(); services.AddTransient <ICurrentUser, CurrentUser>(); services.AddTransient(typeof(IAuditBaseRepository <>), typeof(AuditBaseRepository <>)); services.AddTransient(typeof(IAuditBaseRepository <,>), typeof(AuditBaseRepository <,>)); //services.AddTransient<CustomExceptionMiddleWare>(); services.AddAutoMapper(typeof(UserProfile).Assembly); services.AddControllersWithViews(options => { options.Filters.Add <LinCmsExceptionFilter>(); }) .AddNewtonsoftJson(opt => { //忽略循环引用 opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss"; //设置自定义时间戳格式 opt.SerializerSettings.Converters = new List <JsonConverter>() { new LinCmsTimeConverter() }; // 设置下划线方式,首字母是小写 //opt.SerializerSettings.ContractResolver = new DefaultContractResolver() //{ // NamingStrategy = new SnakeCaseNamingStrategy() // { // ProcessDictionaryKeys = true // } //}; }) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; //自定义 BadRequest 响应 options.InvalidModelStateResponseFactory = context => { var problemDetails = new ValidationProblemDetails(context.ModelState); var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext); return(new BadRequestObjectResult(resultDto) { ContentTypes = { "application/json" } }); }; }); services.AddHttpsRedirection(options => { options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect; options.HttpsPort = 443; }); services.AddHealthChecks(); }
public Lobby(string friendlyName, AuthenticatedUser owner, GameManager gameManager, InMemoryConfiguration inMemoryConfiguration) { this.LobbyId = friendlyName; this.Owner = owner; this.GameManager = gameManager; this.InMemoryConfiguration = inMemoryConfiguration; InitializeAllGameStates(); }
public void MigrateInMemoryDataToSqlServer(IApplicationBuilder app) { using (var scope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope()) { scope.ServiceProvider.GetRequiredService <PersistedGrantDbContext>().Database.Migrate(); var context = scope.ServiceProvider.GetRequiredService <ConfigurationDbContext>(); context.Database.Migrate(); if (!context.Clients.Any()) { foreach (var client in InMemoryConfiguration.Clients()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { foreach (var resource in InMemoryConfiguration.IdentityResources()) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { foreach (var resource in InMemoryConfiguration.ApiResources()) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiScopes.Any()) { foreach (var apiScope in InMemoryConfiguration.ApiScopes()) { context.ApiScopes.Add(apiScope.ToEntity()); } context.SaveChanges(); } var applicationContext = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>(); applicationContext.Database.Migrate(); if (!applicationContext.Users.Any()) { foreach (var user in InMemoryConfiguration.Users()) { var passwordHasher = new PasswordHasher <ApplicationUser>(); var appUser = new ApplicationUser { UserName = "******", NormalizedUserName = "******", CustomElement = "custom element" }; appUser.PasswordHash = passwordHasher.HashPassword(appUser, "Test123!"); applicationContext.Users.Add(appUser); } applicationContext.SaveChanges(); } } }
public void Setup() { _sut = new InMemoryConfiguration(); }
public LobbyController(ILogger <LobbyController> logger, GameManager gameManager, IServiceProvider serviceProvider, InMemoryConfiguration inMemoryConfiguration) { this.GameManager = gameManager; this.Logger = logger; this.ServiceProvider = serviceProvider; this.InMemoryConfiguration = inMemoryConfiguration; }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { InMemoryConfiguration.Configuration = this.Configuration; services.AddSingleton(Fsql); services.AddScoped <IUnitOfWork>(sp => sp.GetService <IFreeSql>().CreateUnitOfWork()); services.AddFreeRepository(filter => { filter.Apply <IDeleteAduitEntity>("IsDeleted", a => a.IsDeleted == false); }, GetType().Assembly, typeof(AuditBaseRepository <>).Assembly); services.AddIdentityServer() #if DEBUG .AddDeveloperSigningCredential() #endif #if DEBUG .AddSigningCredential(new X509Certificate2( Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]), Configuration["Certificates:Password"]) ) #endif .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.GetApis()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddProfileService <LinCmsProfileService>() .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>(); #region Swagger //Swagger重写PascalCase,改成SnakeCase模式 services.TryAddEnumerable(ServiceDescriptor .Transient <IApiDescriptionProvider, SnakeCaseQueryParametersApiDescriptionProvider>()); //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo() { Title = "LinCms.IdentityServer4", Version = "v1" }); var security = new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Id = "Bearer", Type = ReferenceType.SecurityScheme } }, Array.Empty <string>() } }; options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlPath); }); #endregion services.AddTransient <ICurrentUser, CurrentUser>(); services.AddControllers(); }
public void GetByFilterShouldUseDefaultIfPageSizeIfItIsIncorrect() { ISelpConfiguration configuration = new InMemoryConfiguration(); configuration.DefaultPageSize = 11; InitRepositoryParams(true, configuration); int total; var filter = new BaseFilter { PageSize = -55 }; List<FakeEntity> list = repository.GetByFilter(filter, out total); Assert.IsNotNull(list, "Result is null"); Assert.AreEqual(11, list.Count, "Result count is wrong"); Assert.AreEqual(11, filter.PageSize, "Filter hasn't been normalized"); Assert.AreEqual(100, total, "Total is incorrect"); Assert.AreEqual(11, filter.PageSize, "Returned PageSize incorrect"); }
public void MigrateInMemoryDataToSqlServer(IApplicationBuilder app) { using var scope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope(); scope.ServiceProvider.GetRequiredService <PersistedGrantDbContext>().Database.Migrate(); var context = scope.ServiceProvider.GetRequiredService <ConfigurationDbContext>(); context.Database.Migrate(); if (!context.Clients.Any()) { foreach (var client in InMemoryConfiguration.Clients()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { foreach (var resource in InMemoryConfiguration.IdentityResources()) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { foreach (var resource in InMemoryConfiguration.ApiResources()) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiScopes.Any()) { foreach (var apiScope in InMemoryConfiguration.ApiScopes()) { context.ApiScopes.Add(apiScope.ToEntity()); } context.SaveChanges(); } var userManager = scope.ServiceProvider.GetRequiredService <UserManager <ApplicationUser> >(); foreach (var user in InMemoryConfiguration.Users()) { var appUser = userManager.FindByNameAsync(user.Username).Result; if (appUser == null) { appUser = new ApplicationUser { UserName = user.Username, Email = user.Claims.Single(c => c.Type == "email").Value, EmailConfirmed = true }; var result = userManager.CreateAsync(appUser, user.Password).Result; result = userManager.AddClaimsAsync(appUser, new Claim[] { new Claim(JwtClaimTypes.Name, "Nils Gruson"), new Claim(JwtClaimTypes.GivenName, "Nils"), new Claim(JwtClaimTypes.FamilyName, "Gruson") }).Result; } ; } }
public void ConfigureServices(IServiceCollection services) { InMemoryConfiguration.Configuration = this.Configuration; services.AddContext(); services.AddIdentityServer() #if DEBUG .AddDeveloperSigningCredential() #endif #if !DEBUG .AddSigningCredential(new X509Certificate2( Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]), Configuration["Certificates:Password"]) ) #endif .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.GetApis()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddProfileService <LinCmsProfileService>() .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>(); #region Swagger //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo() { Title = "LinCms.IdentityServer4", Version = "v1" }); var security = new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Id = "Bearer", Type = ReferenceType.SecurityScheme } }, Array.Empty <string>() } }; options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlPath); }); #endregion services.AddTransient <IUserRepository, UserRepository>(); services.AddTransient <IUserIdentityService, UserIdentityService>(); services.AddTransient <ICurrentUser, CurrentUser>(); services.AddTransient(typeof(IAuditBaseRepository <>), typeof(AuditBaseRepository <>)); services.AddTransient(typeof(IAuditBaseRepository <,>), typeof(AuditBaseRepository <,>)); services.AddTransient <CustomExceptionMiddleWare>(); services.AddCors(); services.AddAutoMapper(typeof(UserProfile).Assembly); services.AddControllers(options => { //options.Filters.Add<LinCmsExceptionFilter>(); }) .AddNewtonsoftJson(opt => { //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss"; //设置自定义时间戳格式 opt.SerializerSettings.Converters = new List <JsonConverter>() { new LinCmsTimeConverter() }; // 设置下划线方式,首字母是小写 opt.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new SnakeCaseNamingStrategy() { ProcessDictionaryKeys = true } }; }) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; //自定义 BadRequest 响应 options.InvalidModelStateResponseFactory = context => { var problemDetails = new ValidationProblemDetails(context.ModelState); var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext); return(new BadRequestObjectResult(resultDto) { ContentTypes = { "application/json" } }); }; }); services.AddHealthChecks(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { #region IdentityServer4+FreeSql InMemoryConfiguration.Configuration = this.Configuration; services.AddSingleton(Fsql); //services.AddScoped(typeof(IUnitOfWork), typeof(UnitOfWork)); services.AddScoped <IUnitOfWork>(sp => sp.GetService <IFreeSql>().CreateUnitOfWork()); services.AddFreeRepository(filter => { filter.Apply <IDeleteAduitEntity>("IsDeleted", a => a.IsDeleted == false); }, GetType().Assembly, typeof(AuditBaseRepository <>).Assembly); services.AddIdentityServer() #if DEBUG .AddDeveloperSigningCredential() #endif #if !DEBUG .AddSigningCredential(new X509Certificate2(Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]), Configuration["Certificates:Password"])) #endif .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources()) .AddInMemoryApiResources(InMemoryConfiguration.GetApis()) .AddInMemoryClients(InMemoryConfiguration.GetClients()) .AddProfileService <LinCmsProfileService>() .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>(); #region AddAuthentication\AddIdentityServerAuthentication //AddAuthentication()是把验证服务注册到DI, 并配置了Bearer作为默认模式. //AddIdentityServerAuthentication()是在DI注册了token验证的处理者. //由于是本地运行, 所以就不使用https了, RequireHttpsMetadata = false.如果是生产环境, 一定要使用https. //Authority指定Authorization Server的地址. //ApiName要和Authorization Server里面配置ApiResource的name一样. //和 AddJwtBearer不能同时使用,目前还不理解区别。 //services // .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme) // .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options => // { // options.RequireHttpsMetadata = false; // for dev env // options.Authority = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}"; ; // options.ApiName = Configuration["Service:Name"]; // match with configuration in IdentityServer // //options.JwtValidationClockSkew = TimeSpan.FromSeconds(60 * 5); // }); #endregion #region AddJwtBearer services.AddAuthentication(opts => { opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; //opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/cms/oauth2/signin"; options.LogoutPath = "/cms/oauth2/signout"; }) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { //identityserver4 地址 也就是本项目地址 options.Authority = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}"; options.RequireHttpsMetadata = false; options.Audience = Configuration["Service:Name"]; options.TokenValidationParameters = new TokenValidationParameters { // The signing key must match! ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( Encoding.ASCII.GetBytes(Configuration["Authentication:JwtBearer:SecurityKey"])), // Validate the JWT Issuer (iss) claim ValidateIssuer = true, ValidIssuer = Configuration["Authentication:JwtBearer:Issuer"], // Validate the JWT Audience (aud) claim ValidateAudience = true, ValidAudience = Configuration["Authentication:JwtBearer:Audience"], // Validate the token expiry ValidateLifetime = true, // If you want to allow a certain amount of clock drift, set that here //ClockSkew = TimeSpan.Zero }; //options.TokenValidationParameters = new TokenValidationParameters() //{ // ClockSkew = TimeSpan.Zero //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟 //}; //使用Authorize设置为需要登录时,返回json格式数据。 options.Events = new JwtBearerEvents() { OnAuthenticationFailed = context => { //Token expired if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); }, OnChallenge = context => { //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦 context.HandleResponse(); string msg; ErrorCode errorCode; int statusCode = StatusCodes.Status401Unauthorized; if (context.Error == "invalid_token" && context.ErrorDescription == "The token is expired") { msg = "令牌过期"; errorCode = ErrorCode.TokenExpired; statusCode = StatusCodes.Status422UnprocessableEntity; } else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty()) { msg = "令牌失效"; errorCode = ErrorCode.TokenInvalidation; } else { msg = "请先登录";//""认证失败,请检查请求头或者重新登录"; errorCode = ErrorCode.AuthenticationFailed; } context.Response.ContentType = "application/json"; context.Response.StatusCode = statusCode; context.Response.WriteAsync(new ResultDto(errorCode, msg, context.HttpContext).ToString()); return(Task.FromResult(0)); } }; }) .AddGitHub(options => { options.ClientId = Configuration["Authentication:GitHub:ClientId"]; options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"]; options.Scope.Add("user:email"); //authenticateResult.Principal.FindFirst(ClaimTypes.Uri)?.Value; 得到GitHub头像 options.ClaimActions.MapJsonKey(LinConsts.Claims.AvatarUrl, "avatar_url"); options.ClaimActions.MapJsonKey(LinConsts.Claims.BIO, "bio"); options.ClaimActions.MapJsonKey(LinConsts.Claims.BlogAddress, "blog"); }); #endregion #endregion services.AddAutoMapper(typeof(UserProfile).Assembly, typeof(PoemProfile).Assembly); //services.AddCors(option => option.AddPolicy("cors", policy => policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().AllowAnyOrigin())); services.AddCors(); #region Mvc services.AddControllers(options => { options.ValueProviderFactories.Add(new SnakeCaseQueryValueProviderFactory()); //设置SnakeCase形式的QueryString参数 options.Filters.Add <LinCmsExceptionFilter>(); options.Filters.Add <LogActionFilterAttribute>(); // 添加请求方法时的日志记录过滤器 }) .AddNewtonsoftJson(opt => { //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss"; //设置时间戳格式 opt.SerializerSettings.Converters = new List <JsonConverter>() { new LinCmsTimeConverter() }; // 设置下划线方式,首字母是小写 opt.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new SnakeCaseNamingStrategy() { ProcessDictionaryKeys = true } }; }) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; //SuppressUseValidationProblemDetailsForInvalidModelStateResponses; //自定义 BadRequest 响应 options.InvalidModelStateResponseFactory = context => { var problemDetails = new ValidationProblemDetails(context.ModelState); var resultDto = new ResultDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext); return(new BadRequestObjectResult(resultDto) { ContentTypes = { "application/json" } }); }; }); #endregion services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); #region Scrutor 与单个单个注册等价,不过可批量注册 //services.AddScoped<ILogService, LogService>(); //services.AddScoped<IUserSevice, UserService>(); services.Scan(scan => scan //加载Startup这个类所在的程序集 .FromAssemblyOf <IAppService>() // 表示要注册那些类,上面的代码还做了过滤,只留下了以 Service 结尾的类 .AddClasses(classes => classes.Where(t => t.Name != "IFileService" && t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))) .UsingRegistrationStrategy(RegistrationStrategy.Skip) //表示将类型注册为提供其所有公共接口作为服务 .AsImplementedInterfaces() //表示注册的生命周期为 Transient .WithTransientLifetime() // We start out with all types in the assembly of ITransientService .FromAssemblyOf <IScopeDependency>() // AddClasses starts out with all public, non-abstract types in this assembly. // These types are then filtered by the delegate passed to the method. // In this case, we filter out only the classes that are assignable to ITransientService. .AddClasses(classes => classes.AssignableTo <ITransientDependency>()) // We then specify what type we want to register these classes as. // In this case, we want to register the types as all of its implemented interfaces. // So if a type implements 3 interfaces; A, B, C, we'd end up with three separate registrations. .AsImplementedInterfaces() // And lastly, we specify the lifetime of these registrations. .WithTransientLifetime() ); string serviceName = Configuration.GetSection("FILE:SERVICE").Value; if (serviceName == LinFile.LocalFileService) { services.AddTransient <IFileService, LocalFileService>(); } else { services.AddTransient <IFileService, QiniuService>(); } #endregion #region Swagger //Swagger重写PascalCase,改成SnakeCase模式 services.TryAddEnumerable(ServiceDescriptor .Transient <IApiDescriptionProvider, SnakeCaseQueryParametersApiDescriptionProvider>()); //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo() { Title = "LinCms", Version = "v1" }); var security = new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Id = "Bearer", Type = ReferenceType.SecurityScheme } }, Array.Empty <string>() } }; options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlPath); }); #endregion //将Handler注册到DI系统中 services.AddScoped <IAuthorizationHandler, PermissionAuthorizationHandler>(); services.Configure <FormOptions>(options => { options.MultipartBodyLengthLimit = 1024 * 1024 * 2; options.MultipartHeadersCountLimit = 10; }); IConfigurationSection configurationSection = Configuration.GetSection("ConnectionStrings:Default"); services.AddCap(x => { x.UseMySql(configurationSection.Value); x.UseRabbitMQ("localhost"); x.UseDashboard(); x.FailedRetryCount = 5; x.FailedThresholdCallback = (type, msg) => { Console.WriteLine( $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {msg.GetName()}"); }; }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var connectionString = Configuration.GetConnectionString("DefaultConnection"); var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; services.AddSingleton <IServiceConfigurationProxy, ServiceConfigurationProxy>(); services.AddTransient <IVerificationProxy, VerificationProxy>(); services.AddTransient <IAppletUserService, AppletUserService>(); services.AddTransient <IPaymentServiceProxy, PaymentServiceProxy>(); services.Configure <ApplicationSettings>(Configuration.GetSection("ApplicationSettings")); services.AddOptions(); services.AddDbContext <ApplicationDbContext>(options => options.UseMySql(connectionString)); services.AddIdentity <ApplicationUser, IdentityRole>(options => { // 配置身份选项 // 密码配置 options.Password.RequireDigit = false; //是否需要数字(0-9). options.Password.RequiredLength = 6; //设置密码长度最小为6 options.Password.RequireNonAlphanumeric = false; //是否包含非字母或数字字符。 options.Password.RequireUppercase = false; //是否需要大写字母(A-Z). options.Password.RequireLowercase = false; //是否需要小写字母(a-z). // 锁定设置 options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); //账户锁定时长30分钟 options.Lockout.MaxFailedAccessAttempts = 10; //10次失败的尝试将账户锁定 // 用户设置 options.User.RequireUniqueEmail = false; //是否Email地址必须唯一 }) .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders(); // Add application services. services.AddTransient <IEmailSender, EmailSender>(); services.AddIdentityServer() .AddSigningCredential(new X509Certificate2(@"./certificate/gooios.pfx", "!QAZ2wsx098", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable)) .AddTestUsers(InMemoryConfiguration.Users().ToList()) .AddConfigurationStore <ConfigurationCustomDbContext>(options => { options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }) .AddOperationalStore <PersistedGrantCustomDbContext>(options => { options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); options.EnableTokenCleanup = true; options.TokenCleanupInterval = 3600 * 24 * 7; }) .AddAspNetIdentity <ApplicationUser>() //.AddResourceOwnerValidator<SessionKeyValidator>() .AddResourceOwnerValidator <CookAppSessionKeyValidator>() .AddProfileService <ProfileService>(); services.AddMvc(); }