using ZKHK.EntityFramework.Core;
using Furion;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Serilog;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ZKHK.Web.Core
{
public class Startup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCorsAccessor();
services.AddRemoteRequest();
services.AddStackExchangeRedisCache(options =>
{
options.InstanceName = "furion_"; // 键名前缀
options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
{
EndPoints = { { "127.0.0.1", 35679 }, { "127.0.0.1", 35680 }, { "127.0.0.1", 35681 } },
Password = "123456",
ServiceName = "mymaster",
DefaultDatabase = 10,
AllowAdmin = true,
AbortOnConnectFail = false,
KeepAlive = 180,
TieBreaker = "",
CommandMap = StackExchange.Redis.CommandMap.Create(new HashSet//哨兵模式, EXCLUDE a few commands
{
"INFO", "CONFIG", "CLUSTER","PING", "ECHO", "CLIENT"
}, available: false),
//CommandMap = StackExchange.Redis.CommandMap.Sentinel,
};
});
services.AddDbContext(options => options.UseSqlServer(App.Configuration["ConnectionStrings:UseMykeys"]));
//哨兵模式,Redis 配置
var configurationOptions = new StackExchange.Redis.ConfigurationOptions()
{
EndPoints = { { "127.0.0.1", 35679 }, { "127.0.0.1", 35680 }, { "127.0.0.1", 35681 } },
Password = "123456",
ServiceName = "mymaster",
DefaultDatabase = 10,
AllowAdmin = true,
AbortOnConnectFail = false,
KeepAlive = 180,
TieBreaker = "",
CommandMap = StackExchange.Redis.CommandMap.Create(new HashSet//哨兵模式 EXCLUDE a few commands
{
"INFO", "CONFIG", "CLUSTER","PING", "ECHO", "CLIENT"
}, available: false),
//CommandMap = StackExchange.Redis.CommandMap.Sentinel,
};
var redis = StackExchange.Redis.ConnectionMultiplexer.Connect(configurationOptions);//创建Redis实例
//配置 ASP.NET 核心数据保护,初始化数据保护系统时,它会根据操作环境应用默认设置。这些设置通常适用于在单台计算机上运行的应用,但是如果你的web分布在多台服务器上,则需要做配置
//分布式部署建议将秘钥存储在Redis中,或者数据库中,当我们使用基于Cookie的认证的时候,就不会出现[Authorize]认证失败而报 "将您重定向的次数过多"的错误
services.AddDataProtection() // 配置数据保护,应用之间共享受保护的有效负载
.SetApplicationName("SSO")
.PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys"); //将密钥存储在Redis中,可以用于在多台服务器上部署站点,站点之间的cookie数据共享 ,需要引入:Microsoft.AspNetCore.DataProtection.StackExchangeRedis
//.PersistKeysToDbContext() //将秘钥存储在数据库中,可以用于在多台服务器上部署站点,站点之间的cookie数据共享,需要引入:Microsoft.AspNetCore.DataProtection.EntityFrameworkCore(注意版本的兼容问题)
//.PersistKeysToFileSystem(new DirectoryInfo("D:\\share_keys\\")); //将秘钥存储在本地,只能用于单台服务器上部署多个站点,站点之间的cookie数据共享
//.PersistKeysToRegistry(Microsoft.Win32.RegistryKey.FromHandle(null)); //将秘钥存储在注册表中,只能用于单台服务器上部署多个站点,站点之间的cookie数据共享
services.AddAuthentication(options =>//认证
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
services.AddJwt(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = new PathString("/Account/Login");
options.AccessDeniedPath = new PathString("/Errors/ClientError");//资源未通过任何授权策略授权,禁止访问路径
options.LogoutPath = new PathString("/Account/Logout");
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = 403;//如果此处不这样处理,则当出现403无授权的错误时候,则会重定向到/Errors/ClientError 而重定向后Http状态码为200,而不是我们需要的403了
return Task.CompletedTask;
};
options.Cookie.Name = ".AspNet.SharedCookie";//设置统一的Cookie名称
//options.Cookie.Domain = "ZKHK.com.cn";//设置Cookie的域为根域,这样所有子域都可以发现这个Cookie
options.Cookie.Path = "/";
});
services.AddRazorPages().AddFriendlyException().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();//首字母小写
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //避免循环引用
options.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
});
services.AddControllersWithViews().AddInjectWithUnifyResult().AddRazorRuntimeCompilation().AddAppLocalization();//视图预编译、动态编译,及新增语言全球化
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Errors/ServerError");
app.UseStatusCodePagesWithRedirects("/Errors/ClientError?code={0}");
}
app.UseHsts();
app.UseCorsAccessor();
//app.UseHttpsRedirection(); //强制使用HTTPS ,它会将HTTP转换成HTTPS
app.UseAppLocalization();
app.UseStaticFiles();
app.UseSerilogRequestLogging(); // Serilog日志必须在 UseStaticFiles 和 UseRouting 之间
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseInject();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
数据库上下文
///
/// MyKeysContext库上下文,AddDataProtection数据保护,将保护秘钥存储在数据库中,就必须实现IDataProtectionKeyContext接口
///
public class MyKeysContext : DbContext, IDataProtectionKeyContext
{
// A recommended constructor overload when using EF Core
// with dependency injection.
public MyKeysContext(DbContextOptions options)
: base(options) { }
// This maps to the table that stores keys.
public DbSet DataProtectionKeys { get; set; }
}