/// <summary> /// 配置 IdentityServer 服务端 /// nuget包: IdentityServer4 IdentityServer4.EntityFramework /// 1.实现用户验证登陆 /// 2.用户验证成功后通过设置增加API访问权限 /// </summary> /// <param name="services"></param> private void ConfigureIdentityServer(IServiceCollection services) { services.Configure <CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = SameSiteMode.Unspecified; options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); }); var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; services.AddIdentityServer(options => { // 配置用户登录的交互页面,默认为 /Account/Login options.UserInteraction = new UserInteractionOptions { LoginUrl = AppInfo.LoginUrl }; // 设置请求 token 成功后, 写入 token 的 Issuer,设置为"null"后不验证 Issuer. 可在 IdSrv 服务终结点 '/.well-known/openid-configuration' 查看 Issuer // 设置为 null、空字符串或者不设置时: IssuerUri 被默认为为项目监听地址 options.IssuerUri = "null"; options.Authentication.CookieLifetime = TimeSpan.FromHours(0.5); // 用户名密码 验证成功之后,将凭证写入cookie // 在cookie有效期内不需要重新登录, 直接通过凭证获取code ??? }) .AddSigningCredential(AppInfo.Instance.Certificate) // 配置 token 加密的证书 .AddConfigurationStore(options => // 持久化资源、客户端 { options.ConfigureDbContext = builder => builder.UseSqlServer(AppOptions.ResolveConnectionString <string>("Identity"), sqlServerOptionsAction: sqlOptions => { // 配置ConfigurationDbContext在运行时迁移绑定的Assembly sqlOptions.MigrationsAssembly(migrationsAssembly); sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }) .AddOperationalStore(options => // 持久化 授权码、刷新令牌、用户授权信息consents { options.ConfigureDbContext = builder => builder.UseSqlServer(AppOptions.ResolveConnectionString <string>("Identity"), sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(migrationsAssembly); sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); options.EnableTokenCleanup = true; // 配置自动清除令牌 }) .AddProfileService <MyProfileService>() .AddResourceOwnerValidator <MyResourceOwnerPasswordValidator>(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { IMvcBuilder builder = services.AddControllersWithViews(options => { // it doesn't require tokens for requests made using the following safe HTTP methods: GET, HEAD, OPTIONS, and TRACE options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); options.Configure(); }) .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix) .AddDataAnnotationsLocalization() .AddJsonOptions(options => options.JsonSerializerOptions.Configure()) .ConfigureApiBehaviorOptions(options => options.Configure()); #if DEBUG if (Env.IsDevelopment()) { builder.AddRazorRuntimeCompilation(); } #endif services.AddPortableObjectLocalization(options => options.ResourcesPath = "Localization"); services.Configure <RequestLocalizationOptions>(options => { var supportedCultures = new[] { "zh-CN", "en-US" }; options.SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); }); services.AddResponseCompression((options) => { // https://resources.infosecinstitute.com/the-breach-attack/ // Disable compression on dynamically generated pages which over secure connections to avoid security problems. options.EnableForHttps = false; }); // Microsoft.Extensions.Caching.StackExchangeRedis //services.AddStackExchangeRedisCache(options => //{ // options.Configuration = "localhost:5000"; // options.InstanceName = "LightBlogCache"; //}); ConfigureIdentityServer(services); services.AddDbContext <UserDbContext>((sp, options) => { // 闭包 or 反模式 //sp.GetRequiredService<UserDbContext>(); var identityConnStr = AppOptions.ResolveConnectionString <string>("Identity"); options.UseSqlServer(identityConnStr, sqlServerOptionsAction: sqlOptions => { sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }); services.AddTransient <IRepository <User, int>, UserRepository>(); services.AddTransient <IUserService <User>, UserService>(); services.AddScoped <EncryptFormResourceFilterAttribute>(); services.AddSingleton(AppInfo.Instance.Certificate); services.AddScoped <InjectResultActionFilter>(); var jsPath = DashboardRoutes.Routes.Contains("/js[0-9]+") ? "/js[0-9]+" : "/js[0-9]{3}"; //DashboardRoutes.Routes.Append(jsPath, new EmbeddedResourceDispatcher("application/javascript", Assembly.GetExecutingAssembly(),$"{typeof(Startup).Namespace}.HangfireCustomDashboard.hangfire.custom.js")); DashboardRoutes.Routes.Append(jsPath, new StaticFileDispatcher("application/javascript", "js/hangfire.custom.js", Env.WebRootFileProvider)); var IdentityConnStr = AppOptions.ResolveConnectionString <string>("Identity"); services.AddHangfire(x => x.UseSqlServerStorage(IdentityConnStr)); services.AddHangfireServer(); services.AddTransient <IJobManageService, JobManageService>(); services.AddSingleton <JobEntryResolver>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddHostedService <ConsumeScopedServiceHostedService>(); services.AddScoped <IScopedProcessingService, ScopedProcessingService>(); //services.AddDNTCaptcha(options => //// options.UseSessionStorageProvider() // -> It doesn't rely on the server or client's times. Also it's the safest one. //// options.UseMemoryCacheStorageProvider() // -> It relies on the server's times. It's safer than the CookieStorageProvider. //options.UseCookieStorageProvider() // -> It relies on the server and client's times. It's ideal for scalability, because it doesn't save anything in the server's memory //// options.UseDistributedCacheStorageProvider() // --> It's ideal for scalability using `services.AddStackExchangeRedisCache()` for instance. //// Don't set this line (remove it) to use the installed system's fonts (FontName = "Tahoma"). //// Or if you want to use a custom font, make sure that font is present in the wwwroot/fonts folder and also use a good and complete font! //// .UseCustomFont(Path.Combine(_env.WebRootPath, "fonts", "name.ttf")) //// .AbsoluteExpiration(minutes: 7) //// .ShowThousandsSeparators(false); //); services.Configure <MultiTenancyOptions <string> >(Configuration.GetSection("MultiTenancy")); services.PostConfigure <MultiTenancyOptions <string> >(options => { IRequestTenantProvider <string> provider = null; options.RequestTenantProviders.Add(provider); }); }