Exemplo n.º 1
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IBlogArticleServices _blogArticleServices, ILoggerFactory loggerFactory)
        {
            // 记录所有的访问记录
            loggerFactory.AddLog4Net();
            // 记录请求与返回数据
            app.UseReuestResponseLog();
            // signalr
            app.UseSignalRSendMildd();
            // 记录ip请求
            app.UseIPLogMildd();

            #region Environment
            if (env.IsDevelopment())
            {
                // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。
                app.UseDeveloperExceptionPage();

                //app.Use(async (context, next) =>
                //{
                //    //这里会多次调用,这里测试一下就行,不要打开注释
                //    //var blogs =await _blogArticleServices.GetBlogs();
                //    var processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
                //    Console.WriteLine(processName);
                //    await next();
                //});
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection
                //app.UseHsts();
            }
            #endregion

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根据版本名称倒序 遍历展示
                var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
                typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
                {
                    c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
                });
                // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:解决方案名.index.html
                c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.index.html"); //这里是配合MiniProfiler进行性能监控的,《文章:完美基于AOP的接口性能分析》,如果你不需要,可以暂时先注释掉,不影响大局。
                c.RoutePrefix = "";                                                                                       //路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
            });
            #endregion



            // ↓↓↓↓↓↓ 注意下边这些中间件的顺序,很重要 ↓↓↓↓↓↓

            app.UseCors("LimitRequests");

            // 跳转https
            //app.UseHttpsRedirection();
            // 使用静态文件
            app.UseStaticFiles();
            // 使用cookie
            app.UseCookiePolicy();
            // 返回错误码
            app.UseStatusCodePages();//把错误码返回前台,比如是404
            // Routing
            app.UseRouting();
            // 这种自定义授权中间件,可以尝试,但不推荐
            // app.UseJwtTokenAuth();
            // 先开启认证
            app.UseAuthentication();
            // 然后是授权中间件
            app.UseAuthorization();

            // 开启异常中间件,要放到最后
            //app.UseExceptionHandlerMidd();

            app.UseMiniProfiler();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                endpoints.MapHub <ChatHub>("/api2/chatHub");
            });
        }
Exemplo n.º 2
0
        // 注意在CreateDefaultBuilder中,添加Autofac服务工厂
        public void ConfigureContainer(ContainerBuilder builder)
        {
            var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;

            //注册要通过反射创建的组件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();
            builder.RegisterType <BlogCacheAOP>();      //可以直接替换其他拦截器
            builder.RegisterType <BlogRedisCacheAOP>(); //可以直接替换其他拦截器
            builder.RegisterType <BlogLogAOP>();        //这样可以注入第二个
            builder.RegisterType <BlogTranAOP>();

            // ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※

            #region 带有接口层的服务注入

            #region Service.dll 注入,有对应接口
            //获取项目绝对路径,请注意,这个是实现类的dll文件,不是接口 IService.dll ,注入容器当然是Activatore
            try
            {
                var servicesDllFile   = Path.Combine(basePath, "Blog.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", "RedisCachingAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogRedisCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogTranAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogLogAOP));
                }

                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, "Blog.Core.Repository.dll");
                var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
                builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces();
            }
            catch (Exception ex)
            {
                log.Error("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查并拷贝。\n" + ex.Message);

                //throw new Exception("※※★※※ 如果你是第一次下载项目,请先对整个解决方案dotnet build(F6编译),然后再对api层 dotnet run(F5执行),\n因为解耦了,如果你是发布的模式,请检查bin文件夹是否存在Repository.dll和service.dll ※※★※※" + ex.Message + "\n" + ex.InnerException);
            }
            #endregion

            #endregion

            #region 没有接口层的服务层注入

            ////因为没有接口层,所以不能实现解耦,只能用 Load 方法。
            ////注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法
            ////var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services");
            ////builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces);

            #endregion

            #region 没有接口的单独类 class 注入
            ////只能注入该类中的虚方法
            builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
            .EnableClassInterceptors()
            .InterceptedBy(typeof(BlogLogAOP));

            #endregion
        }
Exemplo n.º 3
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // 以下code可能与文章中不一样,对代码做了封装,具体查看右侧 Extensions 文件夹.
            services.AddSingleton(new Appsettings(Configuration));
            services.AddSingleton(new LogLock(Env.ContentRootPath));

            Permissions.IsUseIds4 = Appsettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();

            // 确保从认证中心返回的ClaimType不被更改,不使用Map映射
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddMemoryCacheSetup();
            services.AddRedisCacheSetup();

            services.AddSqlsugarSetup();
            services.AddDbSetup();
            services.AddAutoMapperSetup();
            services.AddCorsSetup();
            services.AddMiniProfilerSetup();
            services.AddSwaggerSetup();
            services.AddJobSetup();
            services.AddHttpContextSetup();
            services.AddAppConfigSetup(Env);
            services.AddHttpApi();
            services.AddRedisInitMqSetup();

            // 授权+认证 (jwt or ids4)
            services.AddAuthorizationSetup();
            if (Permissions.IsUseIds4)
            {
                services.AddAuthentication_Ids4Setup();
            }
            else
            {
                services.AddAuthentication_JWTSetup();
            }

            services.AddIpPolicyRateLimitSetup(Configuration);

            services.AddSignalR().AddNewtonsoftJsonProtocol();

            services.AddScoped <UseServiceDIAttribute>();

            services.Configure <KestrelServerOptions>(x => x.AllowSynchronousIO = true)
            .Configure <IISServerOptions>(x => x.AllowSynchronousIO             = true);

            services.AddControllers(o =>
            {
                // 全局异常过滤
                o.Filters.Add(typeof(GlobalExceptionsFilter));
                // 全局路由权限公约
                //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
                // 全局路由前缀,统一修改路由
                o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
            })
            //全局配置Json序列化处理
            .AddNewtonsoftJson(options =>
            {
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //不使用驼峰样式的key
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                //设置时间格式
                //options.SerializerSettings.DateFormatString = "yyyy-MM-dd";
                //忽略Model中为null的属性
                //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            });

            _services = services;
        }
Exemplo n.º 4
0
        // This method gets called by the runtime. Use this method to add services to the container.
        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 <Blog.Core.Model.Models.DBSeed>();
            services.AddScoped <Blog.Core.Model.Models.MyContext>();
            #endregion

            #region Automapper
            services.AddAutoMapper(typeof(Startup));
            #endregion

            #region CORS
            //跨域第二种方法,声明策略,记得下边app中配置
            services.AddCors(c =>
            {
                //↓↓↓↓↓↓↓注意正式环境不要使用这种全开放的处理↓↓↓↓↓↓↓↓↓↓
                c.AddPolicy("AllRequests", policy =>
                {
                    policy
                    .AllowAnyOrigin()    //允许任何源
                    .AllowAnyMethod()    //允许任何方式
                    .AllowAnyHeader()    //允许任何头
                    .AllowCredentials(); //允许cookie
                });
                //↑↑↑↑↑↑↑注意正式环境不要使用这种全开放的处理↑↑↑↑↑↑↑↑↑↑


                //一般采用这种方法
                c.AddPolicy("LimitRequests", policy =>
                {
                    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, "Blog.Core.xml");            //这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);                              //默认的第二个参数是false,这个是controller的注释,记得修改

                var xmlModelPath = Path.Combine(basePath, "Blog.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);

                //方案名称“Blog.Core”可自定义,上下一致即可
                c.AddSecurityDefinition(IssuerName, new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name        = "Authorization", //jwt默认的参数名称
                    In          = "header",        //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = "apiKey"
                });
                #endregion
            });

            #endregion

            #region MVC + GlobalExceptions

            //注入全局异常捕获
            services.AddMvc(o =>
            {
                // 全局异常过滤
                o.Filters.Add(typeof(GlobalExceptionsFilter));
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            // 取消默认驼峰
            .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new DefaultContractResolver(); });

            #endregion

            #region Authorize权限设置三种情况

            //使用说明:
            //如果你只是简单的基于角色授权的,第一步:【1/2 简单角色授权】,第二步:配置【统一认证】,第三步:开启中间件app.UseMiddleware<JwtTokenAuth>()不能验证过期,或者 app.UseAuthentication();可以验证过期时间
            //如果你是用的复杂的策略授权,配置权限在数据库,第一步:【3复杂策略授权】,第二步:配置【统一认证】,第三步:开启中间件app.UseAuthentication();
            //综上所述,设置权限,必须要三步走,涉及授权策略 + 配置认证 + 开启授权中间件,只不过自定义的中间件不能验证过期时间,所以我都是用官方的。

            #region 【1/2、简单角色授权】
            #region 1、基于角色的API授权

            // 1【授权】、这个很简单,其他什么都不用做,
            // 无需配置服务,只需要在API层的controller上边,增加特性即可,注意,只能是角色的:
            // [Authorize(Roles = "Admin")]

            // 2【认证】、然后在下边的configure里,配置中间件即可:app.UseMiddleware<JwtTokenAuth>();但是这个方法,无法验证过期时间,所以如果需要验证过期时间,还是需要下边的第三种方法,官方认证

            #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"));
            });


            // 2【认证】、然后在下边的configure里,配置中间件即可:app.UseMiddleware<JwtTokenAuth>();但是这个方法,无法验证过期时间,所以如果需要验证过期时间,还是需要下边的第三种方法,官方认证
            #endregion
            #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(60 * 5) //接口的过期时间
                );
            #endregion

            //【授权】
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Permission",
                                  policy => policy.Requirements.Add(permissionRequirement));
            });


            #endregion


            #region 【统一认证】
            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,
                ValidateIssuer           = true,
                ValidIssuer           = audienceConfig["Issuer"],   //发行人
                ValidateAudience      = true,
                ValidAudience         = audienceConfig["Audience"], //订阅人
                ValidateLifetime      = true,
                ClockSkew             = TimeSpan.Zero,
                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);
                    }
                };
            });


            //2.2【认证】、IdentityServer4 认证 (暂时忽略)
            //services.AddAuthentication("Bearer")
            //  .AddIdentityServerAuthentication(options =>
            //  {
            //      options.Authority = "http://localhost:5002";
            //      options.RequireHttpsMetadata = false;
            //      options.ApiName = "blog.core.api";
            //  });
            // 注入权限处理器

            services.AddSingleton <IAuthorizationHandler, PermissionHandler>();
            services.AddSingleton(permissionRequirement);
            #endregion

            #endregion


            #region AutoFac DI
            //实例化 AutoFac  容器
            var builder = new ContainerBuilder();
            //注册要通过反射创建的组件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();
            builder.RegisterType <BlogCacheAOP>();      //可以直接替换其他拦截器
            builder.RegisterType <BlogRedisCacheAOP>(); //可以直接替换其他拦截器
            builder.RegisterType <BlogLogAOP>();        //这样可以注入第二个

            // ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※

            #region 带有接口层的服务注入

            #region Service.dll 注入,有对应接口
            //获取项目绝对路径,请注意,这个是实现类的dll文件,不是接口 IService.dll ,注入容器当然是Activatore
            try
            {
                var servicesDllFile   = Path.Combine(basePath, "Blog.Core.Services.dll");
                var assemblysServices = Assembly.LoadFile(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(BlogRedisCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "LogoAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogLogAOP));
                }

                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, "Blog.Core.Repository.dll");
                var assemblysRepository = Assembly.LoadFile(repositoryDllFile);
                builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces();
            }
            catch (Exception)
            {
                throw new Exception("※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,因为解耦了 ※※★※※");
            }
            #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();

            #endregion

            return(new AutofacServiceProvider(ApplicationContainer));//第三方IOC接管 core内置DI容器
        }
Exemplo n.º 5
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IBlogArticleServices _blogArticleServices, ILoggerFactory loggerFactory)
        {
            #region RecordAllLogs

            if (Appsettings.app("AppSettings", "Middleware_RecordAllLogs", "Enabled").ObjToBool())
            {
                loggerFactory.AddLog4Net();//记录所有的访问记录
            }

            #endregion

            #region ReuestResponseLog

            if (Appsettings.app("AppSettings", "Middleware_RequestResponse", "Enabled").ObjToBool())
            {
                app.UseReuestResponseLog();//记录请求与返回数据
            }

            #endregion

            #region Environment
            if (env.IsDevelopment())
            {
                // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。
                app.UseDeveloperExceptionPage();

                //app.Use(async (context, next) =>
                //{
                //    //这里会多次调用,这里测试一下就行,不要打开注释
                //    //var blogs =await _blogArticleServices.GetBlogs();
                //    var processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
                //    Console.WriteLine(processName);
                //    await next();
                //});
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection
                //app.UseHsts();
            }
            #endregion

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根据版本名称倒序 遍历展示
                typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
                {
                    c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
                });
                // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:解决方案名.index.html
                c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.index.html"); //这里是配合MiniProfiler进行性能监控的,《文章:完美基于AOP的接口性能分析》,如果你不需要,可以暂时先注释掉,不影响大局。
                c.RoutePrefix = "";                                                                                       //路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
            });
            #endregion

            #region MiniProfiler
            app.UseMiniProfiler();
            #endregion

            #region CORS
            //跨域第二种方法,使用策略,详细策略信息在ConfigureService中
            app.UseCors("LimitRequests");//将 CORS 中间件添加到 web 应用程序管线中, 以允许跨域请求。


            #region 跨域第一种版本
            //跨域第一种版本,请要ConfigureService中配置服务 services.AddCors();
            //    app.UseCors(options => options.WithOrigins("http://localhost:8021").AllowAnyHeader()
            //.AllowAnyMethod());
            #endregion

            #endregion

            // 跳转https
            //app.UseHttpsRedirection();
            // 使用静态文件
            app.UseStaticFiles();
            // 使用cookie
            app.UseCookiePolicy();
            // 返回错误码
            app.UseStatusCodePages();//把错误码返回前台,比如是404



            app.UseRouting();

            #region 第三步:开启认证中间件

            //此授权认证方法已经放弃,请使用下边的官方验证方法。但是如果你还想传User的全局变量,还是可以继续使用中间件,第二种写法//app.UseMiddleware<JwtTokenAuth>();
            //app.UseJwtTokenAuth();

            //如果你想使用官方认证,必须在上边ConfigureService 中,配置JWT的认证服务 (.AddAuthentication 和 .AddJwtBearer 二者缺一不可)
            app.UseAuthentication();
            #endregion

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                endpoints.MapHub <ChatHub>("/api2/chatHub");
            });
        }
Exemplo n.º 6
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyContext myContext, ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter, IHostApplicationLifetime lifetime)
        {
            // Ip限流,尽量放管道外层
            app.UseIpLimitMildd();
            // 记录请求与返回数据
            app.UseReuestResponseLog();
            // 用户访问记录(必须放到外层,不然如果遇到异常,会报错,因为不能返回流)
            app.UseRecordAccessLogsMildd();
            // signalr
            app.UseSignalRSendMildd();
            // 记录ip请求
            app.UseIPLogMildd();
            // 查看注入的所有服务
            app.UseAllServicesMildd(_services);

            if (env.IsDevelopment())
            {
                // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection
                //app.UseHsts();
            }

            // 封装Swagger展示
            app.UseSwaggerMildd(() => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.Api.index.html"));

            // ↓↓↓↓↓↓ 注意下边这些中间件的顺序,很重要 ↓↓↓↓↓↓

            // CORS跨域
            app.UseCors(Appsettings.app(new string[] { "Startup", "Cors", "PolicyName" }));
            // 跳转https
            //app.UseHttpsRedirection();
            // 使用静态文件
            app.UseStaticFiles();
            // 使用cookie
            app.UseCookiePolicy();
            // 返回错误码
            app.UseStatusCodePages();
            // Routing
            app.UseRouting();
            // 这种自定义授权中间件,可以尝试,但不推荐
            // app.UseJwtTokenAuth();

            // 测试用户,用来通过鉴权
            if (Configuration.GetValue <bool>("AppSettings:UseLoadTest"))
            {
                app.UseMiddleware <ByPassAuthMidd>();
            }
            // 先开启认证
            app.UseAuthentication();
            // 然后是授权中间件
            app.UseAuthorization();

            // 开启异常中间件,要放到最后
            //app.UseExceptionHandlerMidd();
            // 性能分析
            app.UseMiniProfiler();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                endpoints.MapHub <ChatHub>("/api2/chatHub");
            });

            // 生成种子数据
            app.UseSeedDataMildd(myContext, Env.WebRootPath);
            // 开启QuartzNetJob调度服务
            app.UseQuartzJobMildd(tasksQzServices, schedulerCenter);
            //服务注册
            app.UseConsulMildd(Configuration, lifetime);
        }
Exemplo n.º 7
0
        // This method gets called by the runtime. Use this method to add services to the container.
        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  依赖注入 ISqlSugarClient
            // 这里我不是引用了命名空间,因为如果引用命名空间的话,会和Microsoft的一个GetTypeInfo存在二义性,所以就直接这么使用了。
            services.AddScoped <SqlSugar.ISqlSugarClient>(o =>
            {
                return(new SqlSugar.SqlSugarClient(new SqlSugar.ConnectionConfig()
                {
                    ConnectionString = BaseDBConfig.ConnectionString, //必填, 数据库连接字符串
                    DbType = (SqlSugar.DbType)BaseDBConfig.DbType,    //必填, 数据库类型
                    IsAutoCloseConnection = true,                     //默认false, 时候知道关闭数据库连接, 设置为true无需使用using或者Close操作
                    InitKeyType = SqlSugar.InitKeyType.SystemTable    //默认SystemTable, 字段信息读取, 如:该属性是不是主键,标识列等等信息
                }));
            });
            #endregion
            #region 初始化DB
            //services.AddSingleton<Love>();
            //反向自动生成数据库--不需要注释掉
            services.AddScoped <Blog.Core.Model.See.DBSeed>();
            services.AddScoped <Blog.Core.Model.See.MyContext>();
            #endregion

            #region Automapper
            services.AddAutoMapper(typeof(Startup));
            #endregion

            #region Swagger
            var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
            services.AddSwaggerGen(c =>
            {
                //遍历出全部的版本,做文档信息展示
                typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
                {
                    c.SwaggerDoc(version, new Info
                    {
                        Version        = version,
                        Title          = $"{ApiName} 接口文档",
                        Description    = $"{ApiName} HTTP API ",
                        TermsOfService = "None",
                        Contact        = new Swashbuckle.AspNetCore.Swagger.Contact {
                            Name = "Blog.Core", Email = "*****@*****.**", Url = "http://www.baidu.com"
                        }
                    });//就是这里
                       // 按相对路径排序,作者:Alby
                    c.OrderActionsBy(o => o.RelativePath);
                });

                var xmlPath = Path.Combine(basePath, "Blog.Core.xml"); //这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);                   //默认的第二个参数是false,这个是controller的注释,记得修改


                var xmlModelPath = Path.Combine(basePath, "Blog.Core.Model.xml");//这个就是Model层的xml文件名
                c.IncludeXmlComments(xmlModelPath, true);

                #region Token绑定到ConfigureServices
                //添加header验证信息
                //c.OperationFilter<SwaggerHeader>();
                var security = new Dictionary <string, IEnumerable <string> > {
                    { "Blog.Core", new string[] { } },
                };
                c.AddSecurityRequirement(security);
                //方案名称“Blog.Core”可自定义,上下一致即可
                c.AddSecurityDefinition("Blog.Core", new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name        = "Authorization", //jwt默认的参数名称
                    In          = "header",        //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = "apiKey"
                });
            });

            #endregion
            #region Token服务注册
            services.AddSingleton <IMemoryCache>(factory =>
            {
                var cache = new MemoryCache(new MemoryCacheOptions());
                return(cache);
            });

            #region 参数
            //读取配置文件
            var audienceConfig       = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];
            var keyByteArray         = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey           = new SymmetricSecurityKey(keyByteArray);

            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,
                ValidateIssuer           = true,
                ValidIssuer           = audienceConfig["Issuer"],   //发行人
                ValidateAudience      = true,
                ValidAudience         = audienceConfig["Audience"], //订阅人
                ValidateLifetime      = true,
                ClockSkew             = TimeSpan.Zero,
                RequireExpirationTime = true,
            };

            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(60 * 60) //接口的过期时间
                );
            #endregion

            #region 【第一步:授权】

            #region 1、基于角色的API授权

            // 1【授权】、这个很简单,其他什么都不用做, 只需要在API层的controller上边,增加特性即可,注意,只能是角色的:
            // [Authorize(Roles = "Admin,System")]


            #endregion
            #region 2、基于策略的授权(简单版和复杂版)
            services.AddAuthorization(options =>
            {
                //options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
                //options.AddPolicy("Client1", policy => policy.RequireRole("Client1").Build());
                //options.AddPolicy("Client2", policy => policy.RequireRole("Client2").Build());
                options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
                //这个写法是错误的,这个是并列的关系,不是或的关系
                //options.AddPolicy("AdminOrClient", policy => policy.RequireRole("Admin,Client").Build());

                //这个才是或的关系
                options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
                options.AddPolicy("SystemOrAdminOrOther", policy => policy.RequireRole("Admin", "System", "Other"));
                options.AddPolicy(Permissions.Name,
                                  policy => policy.Requirements.Add(permissionRequirement));
            })    // ② 核心之二,必需要配置认证服务,这里是jwtBearer默认认证,比如光有卡没用,得能识别他们
            .AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            }) // ③ 核心之三,针对JWT的配置,比如门禁是如何识别的,是放射卡,还是磁卡
            .AddJwtBearer(o =>
            {
                o.TokenValidationParameters = tokenValidationParameters;
            });
            #endregion

            #endregion
            //认证
            #region  自定义的认证,自定义认证不够完善,建议使用官方的认证
            //     services.AddAuthentication(x =>
            //     {
            //         x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            //         x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            //     })
            //.AddJwtBearer(o =>
            //{
            //    o.TokenValidationParameters = new TokenValidationParameters
            //    {

            //        ValidateIssuer = true,//是否验证Issuer
            //           ValidateAudience = true,//是否验证Audience
            //           ValidateIssuerSigningKey = true,//是否验证IssuerSigningKey
            //           ValidIssuer = audienceConfig["Issuer"],//发行人
            //           ValidAudience = audienceConfig["Audience"],//订阅人
            //           ValidateLifetime = true,//是否验证超时  当设置exp和nbf时有效 同时启用ClockSkew
            //           IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JwtHelper.secretKey)),
            //           //注意这是缓冲过期时间,总的有效时间等于这个时间加上jwt的过期时间
            //           ClockSkew = TimeSpan.Zero,
            //        RequireExpirationTime = true

            //    };
            //});
            #endregion

            #region 官方认证  暂时注释掉,如果不使用自定义设计可以加上,但不支持定义多个策略
            //这个方案上面已经自定义了,这不需要重复定义,重复定义会报错
            //  services.AddAuthentication("Bearer")
            //// 添加JwtBearer服务
            //.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;
            //        }
            //    };
            //});
            //2.2【认证】、IdentityServer4 认证 (暂时忽略)
            //services.AddAuthentication("Bearer")
            //  .AddIdentityServerAuthentication(options =>
            //  {
            //      options.Authority = "http://localhost:5002";
            //      options.RequireHttpsMetadata = false;
            //      options.ApiName = "blog.core.api";
            //  });
            // 注入权限处理器
            // 依赖注入,将自定义的授权处理器 匹配给官方授权处理器接口,这样当系统处理授权的时候,就会直接访问我们自定义的授权处理器了。
            services.AddSingleton <IAuthorizationHandler, PermissionHandler>();
            // 将授权必要类注入生命周期内
            services.AddSingleton(permissionRequirement);
            #endregion
            #endregion
            #endregion

            #region MiniProfiler性能监听
            services.AddMiniProfiler(options =>
            {
                options.RouteBasePath = "/profiler";//注意这个路径要和下边 index.html 脚本配置中的一致,
                (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
            });
            #endregion
            #region SignalR 通讯
            services.AddSignalR();
            #endregion

            #region CORS 跨域
            //跨域第一种方法,先注入服务,声明策略,然后再下边app中配置开启中间件
            services.AddCors(c =>
            {
                //↓↓↓↓↓↓↓注意正式环境不要使用这种全开放的处理↓↓↓↓↓↓↓↓↓↓
                c.AddPolicy("AllRequests", policy =>
                {
                    policy
                    .AllowAnyOrigin()    //允许任何源
                    .AllowAnyMethod()    //允许任何方式
                    .AllowAnyHeader()    //允许任何头
                    .AllowCredentials(); //允许cookie
                });
                //↑↑↑↑↑↑↑注意正式环境不要使用这种全开放的处理↑↑↑↑↑↑↑↑↑↑


                //一般采用这种方法
                c.AddPolicy("LimitRequests", policy =>
                {
                    policy
                    .WithOrigins("http://127.0.0.1:5000", "http://localhost:8080", "http://localhost:8021", "http://localhost:8081", "http://localhost:5000", "http://localhost:20101", "http://127.0.0.1:20101") //支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
                    .AllowAnyHeader()                                                                                                                                                                             //Ensures that the policy allows any header.
                    .AllowAnyMethod();
                    //.AllowCredentials();
                });
            });
            // 这是第二种注入跨域服务的方法,这里有歧义,部分读者可能没看懂,请看下边解释
            //services.AddCors();
            //跨域第一种版本,请要ConfigureService中配置服务 services.AddCors();
            //    app.UseCors(options => options.WithOrigins("http://localhost:8021").AllowAnyHeader()
            //.AllowAnyMethod());
            #endregion

            services.AddMvc(o =>
            {
                o.Filters.Add(typeof(GlobalExceptionsFilter));
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddSingleton(new Appsettings(Env.ContentRootPath));
            #region AutoFac

            //实例化 AutoFac  容器
            var builder = new ContainerBuilder();

            //注册要通过反射创建的组件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();

            //var assemblysServices = Assembly.Load("Blog.Core.Services");//要记得!!!这个注入的是实现类层,不是接口层!不是 IServices
            //builder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces();//指定已扫描程序集中的类型注册为提供所有其实现的接口。
            //var assemblysRepository = Assembly.Load("Blog.Core.Repository");//模式是 Load(解决方案名)
            //builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces();
            #region 带有接口层的服务注入

            #region Service.dll 注入,有对应接口
            try
            {
                //注册要通过反射创建的组件
                //builder.RegisterType<BlogCacheAOP>();//可以直接替换其他拦截器
                //builder.RegisterType<BlogRedisCacheAOP>();//可以直接替换其他拦截器
                //builder.RegisterType<BlogLogAOP>();//可以直接替换其他拦截器!



                //var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;//获取项目路径
                //var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll");
                //var assemblysServices = Assembly.LoadFrom(servicesDllFile);//直接采用加载文件的方法  ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※

                var servicesDllFile   = Path.Combine(basePath, "Blog.Core.Services.dll");
                var assemblysServices = Assembly.LoadFrom(servicesDllFile);
                //builder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces();

                // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。
                var cacheType = new List <Type>();
                if (Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
                {
                    builder.RegisterType <BlogRedisCacheAOP>();//可以直接替换其他拦截器
                    cacheType.Add(typeof(BlogRedisCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
                {
                    builder.RegisterType <BlogCacheAOP>();//可以直接替换其他拦截器
                    cacheType.Add(typeof(BlogCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
                {
                    builder.RegisterType <BlogLogAOP>();//可以直接替换其他拦截器!
                    cacheType.Add(typeof(BlogLogAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
                {
                    builder.RegisterType <BlogTranAOP>();
                    cacheType.Add(typeof(BlogTranAOP));
                }
                builder.RegisterAssemblyTypes(assemblysServices)
                .AsImplementedInterfaces()
                .InstancePerLifetimeScope()
                .EnableInterfaceInterceptors()        //引用Autofac.Extras.DynamicProxy;
                .InterceptedBy(cacheType.ToArray());  //可以直接替换拦截器


                var repositoryDllFile   = Path.Combine(basePath, "Blog.Core.Repository.dll");
                var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
                builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces()
                .InstancePerDependency();

                #region 没有接口的单独类 class 注入
                ////只能注入该类中的虚方法
                //builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
                //    .EnableClassInterceptors()
                //    .InterceptedBy(typeof(BlogLogAOP));

                #endregion
            }
            catch (Exception ex)
            {
                throw new Exception("※※★※※ 如果你是第一次下载项目,请先对整个解决方案dotnet build(F6编译),然后再对api层 dotnet run(F5执行),\n因为解耦了,如果你是发布的模式,请检查bin文件夹是否存在Repository.dll和service.dll ※※★※※" + ex.Message + "\n" + ex.InnerException);
            }

            #endregion


            #endregion


            //将services填充到Autofac容器生成器中
            builder.Populate(services);

            //使用已进行的组件登记创建新容器
            var ApplicationContainer = builder.Build();
            //ApplicationContainer.Resolve<Love>().SayLoveU();
            #endregion

            return(new AutofacServiceProvider(ApplicationContainer));//第三方IOC接管 core内置DI容器
        }
Exemplo n.º 8
0
        // 注意在CreateDefaultBuilder中,添加Autofac服务工厂
        public void ConfigureContainer(ContainerBuilder builder)
        {
            var basePath = AppContext.BaseDirectory;

            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();


            #region 带有接口层的服务注入


            var servicesDllFile   = Path.Combine(basePath, "Blog.Core.Services.dll");
            var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll");

            if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile)))
            {
                throw new Exception("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。");
            }



            // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。
            var cacheType = new List <Type>();
            if (Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType <BlogRedisCacheAOP>();
                cacheType.Add(typeof(BlogRedisCacheAOP));
            }
            if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType <BlogCacheAOP>();
                cacheType.Add(typeof(BlogCacheAOP));
            }
            if (Appsettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType <BlogTranAOP>();
                cacheType.Add(typeof(BlogTranAOP));
            }
            if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType <BlogLogAOP>();
                cacheType.Add(typeof(BlogLogAOP));
            }
            #endregion

            // 获取 Service.dll 程序集服务,并注册
            var assemblysServices = Assembly.LoadFrom(servicesDllFile);
            builder.RegisterAssemblyTypes(assemblysServices)
            .AsImplementedInterfaces()
            .InstancePerDependency()
            .EnableInterfaceInterceptors()          //引用Autofac.Extras.DynamicProxy;
            .InterceptedBy(cacheType.ToArray());    //允许将拦截器服务的列表分配给注册。

            // 获取 Repository.dll 程序集服务,并注册
            var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
            builder.RegisterAssemblyTypes(assemblysRepository)
            .AsImplementedInterfaces()
            .InstancePerDependency();


            #region 没有接口层的服务层注入

            //因为没有接口层,所以不能实现解耦,只能用 Load 方法。
            //注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法
            //var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services");
            //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces);

            #endregion

            #region 没有接口的单独类 class 注入

            //只能注入该类中的虚方法,且必须是public
            builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
            .EnableClassInterceptors()
            .InterceptedBy(cacheType.ToArray());

            #endregion



            //最大的 gayhub 网站
        }
Exemplo n.º 9
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            #region ReuestResponseLog

            if (Appsettings.app("AppSettings", "Middleware_RequestResponse", "Enabled").ObjToBool())
            {
                app.UseReuestResponseLog();//记录请求与返回数据
            }

            #endregion

            #region Environment
            if (env.IsDevelopment())
            {
                // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection
                //app.UseHsts();
            }
            #endregion

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根据版本名称倒序 遍历展示
                typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
                {
                    c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
                });
                // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:解决方案名.index.html
                c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.index.html"); //这里是配合MiniProfiler进行性能监控的,《文章:完美基于AOP的接口性能分析》,如果你不需要,可以暂时先注释掉,不影响大局。
                c.RoutePrefix = "";                                                                                       //路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉
            });
            #endregion

            #region MiniProfiler
            app.UseMiniProfiler();
            #endregion

            #region 第三步:开启认证中间件

            //此授权认证方法已经放弃,请使用下边的官方验证方法。但是如果你还想传User的全局变量,还是可以继续使用中间件,第二种写法//app.UseMiddleware<JwtTokenAuth>();
            app.UseJwtTokenAuth();

            //如果你想使用官方认证,必须在上边ConfigureService 中,配置JWT的认证服务 (.AddAuthentication 和 .AddJwtBearer 二者缺一不可)
            app.UseAuthentication();
            #endregion

            #region CORS
            //跨域第二种方法,使用策略,详细策略信息在ConfigureService中
            app.UseCors("LimitRequests");//将 CORS 中间件添加到 web 应用程序管线中, 以允许跨域请求。


            #region 跨域第一种版本
            //跨域第一种版本,请要ConfigureService中配置服务 services.AddCors();
            //    app.UseCors(options => options.WithOrigins("http://localhost:8021").AllowAnyHeader()
            //.AllowAnyMethod());
            #endregion

            #endregion


            // 跳转https
            //app.UseHttpsRedirection();
            // 使用静态文件
            app.UseStaticFiles();
            // 使用cookie
            app.UseCookiePolicy();
            // 返回错误码
            app.UseStatusCodePages();//把错误码返回前台,比如是404



            app.UseMvc();


            app.UseSignalR(routes =>
            {
                //这里要说下,为啥地址要写 /api/xxx
                //因为我前后端分离了,而且使用的是代理模式,所以如果你不用/api/xxx的这个规则的话,会出现跨域问题,毕竟这个不是我的controller的路由,而且自己定义的路由
                routes.MapHub <ChatHub>("/api2/chatHub");
            });
        }
Exemplo n.º 10
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // 以下code可能与文章中不一样,对代码做了封装,具体查看右侧 Extensions 文件夹.
            services.AddSingleton(new Appsettings(Configuration));
            services.AddSingleton(new LogLock(Env.ContentRootPath));
            services.AddUiFilesZipSetup(Env);

            Permissions.IsUseIds4 = Appsettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
            RoutePrefix.Name      = Appsettings.app(new string[] { "AppSettings", "SvcName" }).ObjToString();

            // 确保从认证中心返回的ClaimType不被更改,不使用Map映射
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddMemoryCacheSetup();
            services.AddRedisCacheSetup();

            services.AddSqlsugarSetup();
            services.AddDbSetup();
            services.AddAutoMapperSetup();
            services.AddCorsSetup();
            services.AddMiniProfilerSetup();
            services.AddSwaggerSetup();
            services.AddJobSetup();
            services.AddHttpContextSetup();
            //services.AddAppConfigSetup(Env);
            services.AddAppTableConfigSetup(Env);//表格打印配置
            services.AddHttpApi();
            services.AddRedisInitMqSetup();

            services.AddRabbitMQSetup();
            services.AddKafkaSetup(Configuration);
            services.AddEventBusSetup();

            services.AddNacosSetup(Configuration);

            // 授权+认证 (jwt or ids4)
            services.AddAuthorizationSetup();
            if (Permissions.IsUseIds4)
            {
                services.AddAuthentication_Ids4Setup();
            }
            else
            {
                services.AddAuthentication_JWTSetup();
            }

            services.AddIpPolicyRateLimitSetup(Configuration);

            services.AddSignalR().AddNewtonsoftJsonProtocol();

            services.AddScoped <UseServiceDIAttribute>();

            services.Configure <KestrelServerOptions>(x => x.AllowSynchronousIO = true)
            .Configure <IISServerOptions>(x => x.AllowSynchronousIO             = true);

            services.AddDistributedMemoryCache();
            services.AddSession();
            services.AddHttpPollySetup();

            services.AddControllers(o =>
            {
                // 全局异常过滤
                o.Filters.Add(typeof(GlobalExceptionsFilter));
                // 全局路由权限公约
                //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
                // 全局路由前缀,统一修改路由
                o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
            })
            // 这种写法也可以
            //.AddJsonOptions(options =>
            //{
            //    options.JsonSerializerOptions.PropertyNamingPolicy = null;
            //})
            //MVC全局配置Json序列化处理
            .AddNewtonsoftJson(options =>
            {
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //不使用驼峰样式的key
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                //设置时间格式
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //忽略Model中为null的属性
                //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                //设置本地时间而非UTC时间
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                //添加Enum转string
                options.SerializerSettings.Converters.Add(new StringEnumConverter());
            });

            services.Replace(ServiceDescriptor.Transient <IControllerActivator, ServiceBasedControllerActivator>());

            _services = services;
            //支持编码大全 例如:支持 System.Text.Encoding.GetEncoding("GB2312")  System.Text.Encoding.GetEncoding("GB18030")
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }
Exemplo n.º 11
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            #region 部分服务注入-netcore自带方法


            services.AddSingleton(new Appsettings(Configuration));
            services.AddSingleton(new LogLock(Env.ContentRootPath));
            services.AddSingleton <ILoggerHelper, LogHelper>();
            Permissions.IsUseIds4 = Appsettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
            // Redis注入
            services.AddRedisCacheSetup();
            services.AddRedisInitMqSetup();//redis 消息队列
            services.AddMemoryCacheSetup();
            services.AddSqlsugarSetup();
            services.AddDbSetup();
            services.AddAutoMapperSetup();
            services.AddCorsSetup();
            services.AddMiniProfilerSetup();
            services.AddSwaggerSetup();
            services.AddHttpContextSetup();
            services.AddAppConfigSetup();

            services.AddRabbitMQSetup();
            services.AddEventBusSetup();
            #endregion
            // 授权+认证 (jwt or ids4)
            services.AddAuthorizationSetup();
            if (Permissions.IsUseIds4)
            {
                services.AddAuthentication_Ids4Setup();
            }
            else
            {
                services.AddAuthentication_JWTSetup();
            }
            services.AddIpPolicyRateLimitSetup(Configuration);

            services.AddSignalR().AddNewtonsoftJsonProtocol();
            services.AddScoped <UseServiceDIAttribute>();

            //autoface 接口注入必加,否则注入失败报错
            services.Configure <KestrelServerOptions>(x => x.AllowSynchronousIO = true)
            .Configure <IISServerOptions>(x => x.AllowSynchronousIO             = true);

            services.AddControllers(o =>
            {
                // 全局异常过滤
                o.Filters.Add(typeof(GlobalExceptionsFilter));
                // 全局路由权限公约
                //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
                // 全局路由前缀,统一修改路由
                o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
            })
            //全局配置Json序列化处理
            .AddNewtonsoftJson(options =>
            {
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //不使用驼峰样式的key
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                //设置时间格式
                //options.SerializerSettings.DateFormatString = "yyyy-MM-dd";
            });

            _services = services;
        }
Exemplo n.º 12
0
        // This method gets called by the runtime. Use this method to add services to the container.
        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 <Blog.Core.Model.Models.DBSeed>();
            services.AddScoped <Blog.Core.Model.Models.MyContext>();
            #endregion

            #region Automapper
            services.AddAutoMapper(typeof(Startup));
            #endregion

            #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, "Blog.Core.xml");            //这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);                              //默认的第二个参数是false,这个是controller的注释,记得修改

                var xmlModelPath = Path.Combine(basePath, "Blog.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);

                //方案名称“Blog.Core”可自定义,上下一致即可
                c.AddSecurityDefinition(IssuerName, new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name        = "Authorization", //jwt默认的参数名称
                    In          = "header",        //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = "apiKey"
                });
                #endregion
            });

            #endregion

            #region MVC + GlobalExceptions

            //注入全局异常捕获
            services.AddMvc(o =>
            {
                // 全局异常过滤
                o.Filters.Add(typeof(GlobalExceptionsFilter));
                // 全局路由权限公约
                o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
                // 全局路由前缀,统一修改路由
                o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            // 取消默认驼峰
            .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new DefaultContractResolver(); });


            #endregion

            #region TimedJob

            services.AddHostedService <Job1TimedService>();
            services.AddHostedService <Job2TimedService>();

            #endregion

            #region Httpcontext

            // Httpcontext 注入
            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped <IUser, AspNetUser>();

            #endregion

            #region SignalR 通讯
            services.AddSignalR();
            #endregion

            #region Authorize 权限认证三步走

            //Tips:注释中的中括号【xxx】的内容,与下边region中的模块,是一一匹配的

            /*
             * 如果不想走数据库,仅仅想在代码里配置授权,这里可以按照下边的步骤:
             * 1步、【1、基于角色的API授权】
             * 很简单,只需要在指定的接口上,配置特性即可,比如:[Authorize(Roles = "Admin,System,Others")]
             *
             * 但是如果你感觉"Admin,System,Others",这样的字符串太长的话,可以把这个融合到简单策略里
             * 具体的配置,看下文的Region模块【2、基于策略的授权(简单版)】 ,然后在接口上,配置特性:[Authorize(Policy = "A_S_O")]
             *
             *
             * 2步、配置Bearer认证服务,具体代码看下文的 region 【第二步:配置认证服务】
             *
             * 3步、开启中间件
             */



            /*
             * 如果想要把权限配置到数据库,步骤如下:
             * 1步、【3复杂策略授权】
             * 具体的查看下边 region 内的内容
             *
             * 2步、配置Bearer认证服务,具体代码看下文的 region 【第二步:配置认证服务】
             *
             * 3步、开启中间件
             */



            //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"));
                options.AddPolicy("A_S_O", policy => policy.RequireRole("Admin", "System", "Others"));
            });


            #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(60 * 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认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
            // 添加JwtBearer服务
            .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);
                    }
                };
            });


            //2.2【认证】、IdentityServer4 认证 (暂时忽略)
            //services.AddAuthentication("Bearer")
            //  .AddIdentityServerAuthentication(options =>
            //  {
            //      options.Authority = "http://localhost:5002";
            //      options.RequireHttpsMetadata = false;
            //      options.ApiName = "blog.core.api";
            //  });
            // 注入权限处理器

            services.AddSingleton <IAuthorizationHandler, PermissionHandler>();
            services.AddSingleton(permissionRequirement);
            #endregion

            #endregion

            services.AddSingleton(new Appsettings(Env));
            services.AddSingleton(new LogLock(Env));


            #region AutoFac DI
            //实例化 AutoFac  容器
            var builder = new ContainerBuilder();
            //注册要通过反射创建的组件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();
            builder.RegisterType <BlogCacheAOP>();      //可以直接替换其他拦截器
            builder.RegisterType <BlogRedisCacheAOP>(); //可以直接替换其他拦截器
            builder.RegisterType <BlogLogAOP>();        //这样可以注入第二个

            // ※※★※※ 如果你是第一次下载项目,请先F6编译,然后再F5执行,※※★※※

            #region 带有接口层的服务注入

            #region Service.dll 注入,有对应接口
            //获取项目绝对路径,请注意,这个是实现类的dll文件,不是接口 IService.dll ,注入容器当然是Activatore
            try
            {
                var servicesDllFile   = Path.Combine(basePath, "Blog.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", "RedisCachingAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogRedisCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogCacheAOP));
                }
                if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
                {
                    cacheType.Add(typeof(BlogLogAOP));
                }

                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, "Blog.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 ※※★※※" + ex.Message + "\n" + ex.InnerException);
            }
            #endregion
            #endregion


            #region 没有接口层的服务层注入

            ////因为没有接口层,所以不能实现解耦,只能用 Load 方法。
            ////注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法
            ////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();

            #endregion

            return(new AutofacServiceProvider(ApplicationContainer));//第三方IOC接管 core内置DI容器
        }
Exemplo n.º 13
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            #region 依赖注入
            services.AddSingleton(new Appsettings(Configuration));
            #endregion
            services.AddControllers();
            #region Swagger
            var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("V1", new OpenApiInfo
                {
                    // {ApiName} 定义成全局变量,方便修改
                    Version     = "V1",
                    Title       = $"{ApiName} 接口文档——Net 5",
                    Description = $"{ApiName} HTTP API V1",
                    //Contact = new OpenApiContact { Name = ApiName, Email = "*****@*****.**", Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") },
                    //License = new OpenApiLicense { Name = ApiName, Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") }
                });
                //c.OrderActionsBy(o => o.RelativePath);
                var xmlPath = Path.Combine(basePath, "blog.core.xml"); //这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);                   //默认的第二个参数是false,这个是controller的注释,记得修改
                                                                       // Jwt Bearer 认证,必须是 oauth2
                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name        = "Authorization",          //jwt默认的参数名称
                    In          = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = SecuritySchemeType.ApiKey
                });
                // 开启加权小锁
                c.OperationFilter <AddResponseHeadersFilter>();
                c.OperationFilter <AppendAuthorizeToSummaryOperationFilter>();

                // 在header中添加token,传递到后台
                c.OperationFilter <SecurityRequirementsOperationFilter>();
            });
            #endregion

            #region 认证
            //读取配置文件
            var symmetricKeyAsBase64 = Appsettings.app(new string[] { "Audience", "Secret" });
            var keyByteArray         = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey           = new SymmetricSecurityKey(keyByteArray);
            var signingCredentials   = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            services.AddAuthentication(x =>
            {
                //看这个单词熟悉么?没错,就是上边错误里的那个。
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })// 也可以直接写字符串,AddAuthentication("Bearer")
            .AddJwtBearer(o =>
            {
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = signingKey,
                    ValidateIssuer           = true,
                    ValidIssuer           = Appsettings.app(new string[] { "Audience", "Issuer" }),   //audienceConfig["Issuer"],//发行人
                    ValidateAudience      = true,
                    ValidAudience         = Appsettings.app(new string[] { "Audience", "Audience" }), //audienceConfig["Audience"],//订阅人
                    ValidateLifetime      = true,
                    ClockSkew             = TimeSpan.Zero,                                            //这个是缓冲过期时间,也就是说,即使我们配置了过期时间,这里也要考虑进去,过期时间+缓冲,默认好像是7分钟,你可以直接设置为0
                    RequireExpirationTime = true,
                };
            });
            #endregion
            #region FreeSql
            string   MysqlConnStr = Configuration.GetConnectionString("MySql");
            IFreeSql fsql         = new FreeSql.FreeSqlBuilder()
                                    .UseConnectionString(FreeSql.DataType.MySql, MysqlConnStr)
                                    .UseLazyLoading(true)        //开启延时加载功能
                                    .UseAutoSyncStructure(false) //自动同步实体结构到数据库
                                    .Build();                    //请务必定义成 Singleton 单例模式
            services.AddSingleton(fsql);
            //注意: IFreeSql 在项目中应以单例声明,而不是在每次使用的时候创建。
            #endregion
        }