// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvc(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } using (var serviceScope = app.ApplicationServices.GetService <IServiceScopeFactory>().CreateScope()) { var context = serviceScope.ServiceProvider.GetRequiredService <DomainDbContext>(); context.Database.EnsureCreated(); } QuartzRegister.Run(Container).GetAwaiter().GetResult(); }
public IServiceProvider ConfigureServices(IServiceCollection services) { #region 部分服务注入-netcore自带方法 // 缓存注入 services.AddScoped <ICaching, MemoryCaching>(); services.AddSingleton <IMemoryCache>(factory => { var cache = new MemoryCache(new MemoryCacheOptions()); return(cache); }); // Redis注入 services.AddSingleton <IRedisCacheManager, RedisCacheManager>(); // log日志注入 services.AddSingleton <ILoggerHelper, LogHelper>(); #endregion #region 初始化DB services.AddScoped <MyBlog.Core.Model.Models.MyContext>(); #endregion // Automapper 注入 services.AddAutoMapperSetup(); #region CORS //跨域第二种方法,声明策略,记得下边app中配置 services.AddCors(c => { //↓↓↓↓↓↓↓注意正式环境不要使用这种全开放的处理↓↓↓↓↓↓↓↓↓↓ c.AddPolicy("AllRequests", policy => { policy .AllowAnyOrigin() //允许任何源 .AllowAnyMethod() //允许任何方式 .AllowAnyHeader() //允许任何头 .AllowCredentials(); //允许cookie }); //↑↑↑↑↑↑↑注意正式环境不要使用这种全开放的处理↑↑↑↑↑↑↑↑↑↑ //一般采用这种方法 c.AddPolicy("LimitRequests", policy => { // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的 // 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的,尽量写两个 policy .WithOrigins("http://127.0.0.1:1818", "http://*****:*****@xxx.com", Url = "https://www.jianshu.com/u/94102b59cc2a" } }); // 按相对路径排序,作者:Alby c.OrderActionsBy(o => o.RelativePath); }); //就是这里 var xmlPath = Path.Combine(basePath, "MyBlog.Core.Web.xml"); //这个就是刚刚配置的xml文件名 c.IncludeXmlComments(xmlPath, true); //默认的第二个参数是false,这个是controller的注释,记得修改 var xmlModelPath = Path.Combine(basePath, "MyBlog.Core.Model.xml"); //这个就是Model层的xml文件名 c.IncludeXmlComments(xmlModelPath); #region Token绑定到ConfigureServices //添加header验证信息 //c.OperationFilter<SwaggerHeader>(); // 发行人 var IssuerName = (Configuration.GetSection("Audience"))["Issuer"]; var security = new Dictionary <string, IEnumerable <string> > { { IssuerName, new string[] { } }, }; c.AddSecurityRequirement(security); //方案名称“MyBlog.Core.Web”可自定义,上下一致即可 c.AddSecurityDefinition(IssuerName, new ApiKeyScheme { Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", Name = "Authorization", //jwt默认的参数名称 In = "header", //jwt默认存放Authorization信息的位置(请求头中) Type = "apiKey" }); #endregion }); #endregion #region Authorize 权限认证三步走 //使用说明: //1、如果你只是简单的基于角色授权的,仅仅在 api 上配置,第一步:【1/2 简单角色授权】,第二步:配置【统一认证服务】,第三步:开启中间件 //2、如果你是用的复杂的基于策略授权,配置权限在数据库,第一步:【3复杂策略授权】,第二步:配置【统一认证服务】,第三步:开启中间件app.UseAuthentication(); //3、综上所述,设置权限,必须要三步走,授权 + 配置认证服务 + 开启授权中间件,只不过自定义的中间件不能验证过期时间,所以我都是用官方的。 #region 【第一步:授权】 #region 1、基于角色的API授权 // 1【授权】、这个很简单,其他什么都不用做, 只需要在API层的controller上边,增加特性即可,注意,只能是角色的: // [Authorize(Roles = "Admin,System")] #endregion #region 2、基于策略的授权(简单版) // 1【授权】、这个和上边的异曲同工,好处就是不用在controller中,写多个 roles 。 // 然后这么写 [Authorize(Policy = "Admin")] services.AddAuthorization(options => { options.AddPolicy("Client", policy => policy.RequireRole("Client").Build()); options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build()); options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System")); }); #endregion #region 【3、复杂策略授权】 #region 参数 //读取配置文件 var audienceConfig = Configuration.GetSection("Audience"); var symmetricKeyAsBase64 = audienceConfig["Secret"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); // 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值 var permission = new List <PermissionItem>(); // 角色与接口的权限要求参数 var permissionRequirement = new PermissionRequirement( "/api/denied", // 拒绝授权的跳转地址(目前无用) permission, ClaimTypes.Role, //基于角色的授权 audienceConfig["Issuer"], //发行人 audienceConfig["Audience"], //听众 signingCredentials, //签名凭据 expiration: TimeSpan.FromSeconds(1 * 60) //接口的过期时间 ); #endregion //【授权】 services.AddAuthorization(options => { options.AddPolicy(Permissions.Name, policy => policy.Requirements.Add(permissionRequirement)); }); #endregion #endregion #region 【第二步:配置认证服务】 // 令牌验证参数 var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = audienceConfig["Issuer"], //发行人 ValidateAudience = true, ValidAudience = audienceConfig["Audience"], //订阅人 ValidateLifetime = true, ClockSkew = TimeSpan.FromSeconds(30), RequireExpirationTime = true, }; //2.1【认证】、core自带官方JWT认证 services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = tokenValidationParameters; o.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // 如果过期,则把<是否过期>添加到,返回头信息中 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); } }; }); services.AddSingleton <IAuthorizationHandler, PermissionHandler>(); services.AddSingleton(permissionRequirement); #endregion #endregion #region AutoFac DI //实例化 AutoFac 容器 var builder = new ContainerBuilder(); //注册要通过反射创建的组件 //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>(); builder.RegisterType <LuoKiPetCacheAOP>(); //可以直接替换其他拦截器 builder.RegisterType <LuoKiPetRedisCacheAOP>(); //可以直接替换其他拦截器 builder.RegisterType <LuoKiPetLogAOP>(); //这样可以注入第二个 builder.RegisterModule(new QuartzAutofacFactoryModule() { ConfigurationProvider = (provider) => { var properties = new NameValueCollection(); // 设置线程池 properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"; //设置线程池的最大线程数量 properties["quartz.threadPool.threadCount"] = "5"; //设置作业中每个线程的优先级 properties["quartz.threadPool.threadPriority"] = ThreadPriority.Normal.ToString(); return(properties); } }); builder.RegisterModule(new QuartzAutofacJobsModule(typeof(MyBlog.Core.Web.Jobs.Core.JobManager).Assembly)); // ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※ #region 带有接口层的服务注入 #region Service.dll 注入,有对应接口 //获取项目绝对路径,请注意,这个是实现类的dll文件,不是接口 IService.dll ,注入容器当然是Activatore try { var servicesDllFile = Path.Combine(basePath, "MyBlog.Core.Services.dll"); var assemblysServices = Assembly.LoadFrom(servicesDllFile);//直接采用加载文件的方法 ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※ //builder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces();//指定已扫描程序集中的类型注册为提供所有其实现的接口。 // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。 var cacheType = new List <Type>(); if (Appsettings.app(new string[] { "AppSettings", "RedisCaching", "Enabled" }).ObjToBool()) { cacheType.Add(typeof(LuoKiPetRedisCacheAOP)); } if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool()) { cacheType.Add(typeof(LuoKiPetCacheAOP)); } if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool()) { cacheType.Add(typeof(LuoKiPetLogAOP)); } builder.RegisterAssemblyTypes(assemblysServices) .AsImplementedInterfaces() .InstancePerLifetimeScope() .EnableInterfaceInterceptors() //引用Autofac.Extras.DynamicProxy; // 如果你想注入两个,就这么写 InterceptedBy(typeof(BlogCacheAOP), typeof(BlogLogAOP)); // 如果想使用Redis缓存,请必须开启 redis 服务,端口号我的是6319,如果不一样还是无效,否则请使用memory缓存 BlogCacheAOP .InterceptedBy(cacheType.ToArray()); //允许将拦截器服务的列表分配给注册。 #endregion #region Repository.dll 注入,有对应接口 var repositoryDllFile = Path.Combine(basePath, "MyBlog.Core.Repository.dll"); var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces(); } catch (Exception ex) { throw new Exception("※※★※※ 如果你是第一次下载项目,请先对整个解决方案dotnet build(F6编译),然后再对api层 dotnet run(F5执行),\n因为解耦了,如果你是发布的模式,请检查bin文件夹是否存在Repository.dll和service.dll ※※★※※"); } #endregion #endregion #region 没有接口层的服务层注入 ////因为没有接口层,所以不能实现解耦,只能用 Load 方法。 ////var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services"); ////builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces); #endregion #region 没有接口的单独类 class 注入 ////只能注入该类中的虚方法 //builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love))) // .EnableClassInterceptors() // .InterceptedBy(typeof(BlogLogAOP)); #endregion //将services填充到Autofac容器生成器中 builder.Populate(services); //使用已进行的组件登记创建新容器 var ApplicationContainer = builder.Build(); QuartzRegister.UseQuartz(ApplicationContainer); #endregion return(new AutofacServiceProvider(ApplicationContainer));//第三方IOC接管 core内置DI容器 }