public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateUpdateBookDto createBook)
        {
            await _bookService.CreateAsync(createBook);

            return(UnifyResponseDto.Success("新建图书成功"));
        }
        public void ConfigureServices(IServiceCollection services)
        {
            InMemoryConfiguration.Configuration = this.Configuration;

            services.AddContext();

            services.AddIdentityServer()
#if DEBUG
            .AddDeveloperSigningCredential()
#endif
#if !DEBUG
            .AddSigningCredential(new X509Certificate2(
                                      Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]),
                                      Configuration["Certificates:Password"])
                                  )
#endif
            .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources())
            .AddInMemoryApiResources(InMemoryConfiguration.GetApis())
            .AddInMemoryClients(InMemoryConfiguration.GetClients())
            .AddProfileService <LinCmsProfileService>()
            .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>();

            #region Swagger

            //Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title = "LinCms.IdentityServer4", Version = "v1"
                });
                var security = new OpenApiSecurityRequirement()
                {
                    { new OpenApiSecurityScheme
                      {
                          Reference = new OpenApiReference()
                          {
                              Id   = "Bearer",
                              Type = ReferenceType.SecurityScheme
                          }
                      }, Array.Empty <string>() }
                };
                options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                    Name        = "Authorization",          //jwt默认的参数名称
                    In          = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = SecuritySchemeType.ApiKey
                });

                string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml");
                options.IncludeXmlComments(xmlPath);
            });
            #endregion

            services.AddTransient <IUserRepository, UserRepository>();
            services.AddTransient <IUserIdentityService, UserIdentityService>();
            services.AddTransient <ICurrentUser, CurrentUser>();
            services.AddTransient(typeof(IAuditBaseRepository <>), typeof(AuditBaseRepository <>));
            services.AddTransient(typeof(IAuditBaseRepository <,>), typeof(AuditBaseRepository <,>));
            services.AddTransient <CustomExceptionMiddleWare>();

            services.AddCors();
            services.AddAutoMapper(typeof(UserProfile).Assembly);

            services.AddControllers(options =>
            {
                //options.Filters.Add<LinCmsExceptionFilter>();
            })
            .AddNewtonsoftJson(opt =>
            {
                //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss";
                //设置自定义时间戳格式
                opt.SerializerSettings.Converters = new List <JsonConverter>()
                {
                    new LinCmsTimeConverter()
                };
                // 设置下划线方式,首字母是小写
                opt.SerializerSettings.ContractResolver = new DefaultContractResolver()
                {
                    NamingStrategy = new SnakeCaseNamingStrategy()
                    {
                        ProcessDictionaryKeys = true
                    }
                };
            })
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressConsumesConstraintForFormFileParameters = true;
                //自定义 BadRequest 响应
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = new ValidationProblemDetails(context.ModelState);

                    var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext);

                    return(new BadRequestObjectResult(resultDto)
                    {
                        ContentTypes = { "application/json" }
                    });
                };
            });
            services.AddHealthChecks();
        }
        public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateUpdateBaseTypeDto createBaseType)
        {
            await _baseTypeService.CreateAsync(createBaseType);

            return(UnifyResponseDto.Success("新建类别成功"));
        }
Example #4
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddContext();
            #region IdentityServer4

            #region AddAuthentication\AddIdentityServerAuthentication
            //AddAuthentication()是把验证服务注册到DI, 并配置了Bearer作为默认模式.

            //AddIdentityServerAuthentication()是在DI注册了token验证的处理者.
            //由于是本地运行, 所以就不使用https了, RequireHttpsMetadata = false.如果是生产环境, 一定要使用https.
            //Authority指定Authorization Server的地址.
            //ApiName要和Authorization Server里面配置ApiResource的name一样.
            //和  AddJwtBearer不能同时使用,目前还不理解区别。
            //services
            //    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            //    .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options =>
            //    {
            //        options.RequireHttpsMetadata = false; // for dev env
            //        options.Authority = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}"; ;
            //        options.ApiName = Configuration["Service:Name"]; // match with configuration in IdentityServer

            //        //options.JwtValidationClockSkew = TimeSpan.FromSeconds(60 * 5);

            //    });
            #endregion

            #region AddJwtBearer
            services.AddAuthentication(opts =>
            {
                opts.DefaultScheme             = CookieAuthenticationDefaults.AuthenticationScheme;
                opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.LoginPath  = "/cms/oauth2/signin";
                options.LogoutPath = "/cms/oauth2/signout";
            })
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                //identityserver4 地址 也就是本项目地址
                options.Authority            = $"{Configuration["Identity:Protocol"]}://{Configuration["Identity:IP"]}:{Configuration["Identity:Port"]}";
                options.RequireHttpsMetadata = false;
                options.Audience             = Configuration["Service:Name"];

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    // The signing key must match!
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = new SymmetricSecurityKey(
                        Encoding.ASCII.GetBytes(Configuration["Authentication:JwtBearer:SecurityKey"])),

                    // Validate the JWT Issuer (iss) claim
                    ValidateIssuer = true,
                    ValidIssuer    = Configuration["Authentication:JwtBearer:Issuer"],

                    // Validate the JWT Audience (aud) claim
                    ValidateAudience = true,
                    ValidAudience    = Configuration["Authentication:JwtBearer:Audience"],

                    // Validate the token expiry
                    ValidateLifetime = true,

                    // If you want to allow a certain amount of clock drift, set that here
                    //ClockSkew = TimeSpan.Zero
                };

                //options.TokenValidationParameters = new TokenValidationParameters()
                //{
                //    ClockSkew = TimeSpan.Zero   //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟
                //};


                //使用Authorize设置为需要登录时,返回json格式数据。
                options.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = context =>
                    {
                        //Token expired
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return(Task.CompletedTask);
                    },
                    OnChallenge = context =>
                    {
                        //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦
                        context.HandleResponse();

                        string message;
                        ErrorCode errorCode;
                        int statusCode = StatusCodes.Status401Unauthorized;

                        if (context.Error == "invalid_token" &&
                            context.ErrorDescription == "The token is expired")
                        {
                            message    = "令牌过期";
                            errorCode  = ErrorCode.TokenExpired;
                            statusCode = StatusCodes.Status422UnprocessableEntity;
                        }
                        else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty())
                        {
                            message   = "令牌失效";
                            errorCode = ErrorCode.TokenInvalidation;
                        }

                        else
                        {
                            message   = "请先登录";  //""认证失败,请检查请求头或者重新登录";
                            errorCode = ErrorCode.AuthenticationFailed;
                        }

                        context.Response.ContentType = "application/json";
                        context.Response.StatusCode  = statusCode;
                        context.Response.WriteAsync(new UnifyResponseDto(errorCode, message, context.HttpContext).ToString());

                        return(Task.FromResult(0));
                    }
                };
            })
            .AddGitHub(options =>
            {
                options.ClientId     = Configuration["Authentication:GitHub:ClientId"];
                options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"];
                options.Scope.Add("user:email");
                //authenticateResult.Principal.FindFirst(ClaimTypes.Uri)?.Value;  得到GitHub头像
                options.ClaimActions.MapJsonKey(LinConsts.Claims.AvatarUrl, "avatar_url");
                options.ClaimActions.MapJsonKey(LinConsts.Claims.BIO, "bio");
                options.ClaimActions.MapJsonKey(LinConsts.Claims.BlogAddress, "blog");
            });
            #endregion

            #endregion

            services.AddCsRedisCore();

            services.AddAutoMapper(typeof(UserProfile).Assembly, typeof(PoemProfile).Assembly);

            services.AddCors();

            #region Mvc
            services.AddControllers(options =>
            {
                options.ValueProviderFactories.Add(new SnakeCaseQueryValueProviderFactory()); //设置SnakeCase形式的QueryString参数
                //options.Filters.Add<LinCmsExceptionFilter>();
                options.Filters.Add <LogActionFilterAttribute>();                             // 添加请求方法时的日志记录过滤器
            })
            .AddNewtonsoftJson(opt =>
            {
                //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss";
                //设置时间戳格式
                opt.SerializerSettings.Converters = new List <JsonConverter>()
                {
                    new LinCmsTimeConverter()
                };
                // 设置下划线方式,首字母是小写
                opt.SerializerSettings.ContractResolver = new DefaultContractResolver()
                {
                    NamingStrategy = new SnakeCaseNamingStrategy()
                    {
                        ProcessDictionaryKeys = true
                    }
                };
            })
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressConsumesConstraintForFormFileParameters = true; //SuppressUseValidationProblemDetailsForInvalidModelStateResponses;
                //自定义 BadRequest 响应
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = new ValidationProblemDetails(context.ModelState);

                    var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext);

                    return(new BadRequestObjectResult(resultDto)
                    {
                        ContentTypes = { "application/json" }
                    });
                };
            });
            #endregion

            services.AddServices();

            string serviceName = Configuration.GetSection("FILE:SERVICE").Value;

            if (serviceName == LinFile.LocalFileService)
            {
                services.AddTransient <IFileService, LocalFileService>();
            }
            else
            {
                services.AddTransient <IFileService, QiniuService>();
            }

            #region Swagger
            //Swagger重写PascalCase,改成SnakeCase模式
            services.TryAddEnumerable(ServiceDescriptor
                                      .Transient <IApiDescriptionProvider, SnakeCaseQueryParametersApiDescriptionProvider>());

            //Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title = "LinCms", Version = "v1"
                });
                var security = new OpenApiSecurityRequirement()
                {
                    { new OpenApiSecurityScheme
                      {
                          Reference = new OpenApiReference()
                          {
                              Id   = "Bearer",
                              Type = ReferenceType.SecurityScheme
                          }
                      }, Array.Empty <string>() }
                };
                options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                    Name        = "Authorization",          //jwt默认的参数名称
                    In          = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = SecuritySchemeType.ApiKey
                });

                string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml");
                options.IncludeXmlComments(xmlPath);
            });
            #endregion


            services.Configure <FormOptions>(options =>
            {
                options.MultipartBodyLengthLimit   = 1024 * 1024 * 2;
                options.MultipartHeadersCountLimit = 10;
            });

            IConfigurationSection configurationSection = Configuration.GetSection("ConnectionStrings:MySql");
            services.AddCap(x =>
            {
                x.UseMySql(configurationSection.Value);

                x.UseRabbitMQ(options =>
                {
                    options.HostName    = Configuration["RabbitMQ:HostName"];
                    options.UserName    = Configuration["RabbitMQ:UserName"];
                    options.Password    = Configuration["RabbitMQ:Password"];
                    options.VirtualHost = Configuration["RabbitMQ:VirtualHost"];
                });

                x.UseDashboard();
                x.FailedRetryCount        = 5;
                x.FailedThresholdCallback = (type, message) =>
                {
                    Console.WriteLine(
                        $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {message.GetName()}");
                };
            });
            services.AddStartupTask <MigrationStartupTask>();
            services.AddHealthChecks();
        }
Example #5
0
 public UnifyResponseDto CreateAsync([FromBody] ResourceDto createResource)
 {
     _resourceService.CreateAsync(createResource);
     return(UnifyResponseDto.Success("新建成功"));
 }
Example #6
0
        public async Task <UnifyResponseDto> UpdateAsync(long id, [FromBody] CreateUpdateDocDto updateDoc)
        {
            await _docService.UpdateAsync(id, updateDoc);

            return(UnifyResponseDto.Success("编辑文档成功"));
        }
Example #7
0
        public async Task <UnifyResponseDto> UpdateAsync(Guid id, [FromBody] CreateUpdateTagDto updateTag)
        {
            await _tagService.UpdateAsync(id, updateTag);

            return(UnifyResponseDto.Success("更新标签成功"));
        }
Example #8
0
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddFreeSql(Configuration);

            services.AddCsRedisCore(Configuration);

            services.AddJwtBearer(Configuration);

            services.AddAutoMapper(typeof(UserProfile).Assembly, typeof(PoemProfile).Assembly);

            services.AddCors();

            #region Mvc
            services.AddMvc(options =>
            {
                options.ValueProviderFactories.Add(new ValueProviderFactory()); //设置SnakeCase形式的QueryString参数
                //options.Filters.Add<LogActionFilterAttribute>(); // 添加请求方法时的日志记录过滤器
                options.Filters.Add <LinCmsExceptionFilter>();                  //
            })
            .AddNewtonsoftJson(opt =>
            {
                opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss";
                // 设置自定义时间戳格式
                opt.SerializerSettings.Converters = new List <JsonConverter>()
                {
                    new LinCmsTimeConverter()
                };
                // 设置下划线方式,首字母是小写
                opt.SerializerSettings.ContractResolver = new DefaultContractResolver()
                {
                    NamingStrategy = new SnakeCaseNamingStrategy()
                    {
                        //ProcessDictionaryKeys = true
                    },
                };
            })
            .ConfigureApiBehaviorOptions(options =>
            {
                //options.SuppressConsumesConstraintForFormFileParameters = true; //SuppressUseValidationProblemDetailsForInvalidModelStateResponses;
                //自定义 BadRequest 响应
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = new ValidationProblemDetails(context.ModelState);
                    var resultDto      = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext);

                    return(new BadRequestObjectResult(resultDto)
                    {
                        ContentTypes = { "application/json" }
                    });
                };
            });
            #endregion



            //配置Google验证码
            services.AddScoped <RecaptchaVerifyActionFilter>();
            services.Configure <GooglereCAPTCHAOptions>(Configuration.GetSection(GooglereCAPTCHAOptions.RecaptchaSettings));
            GooglereCAPTCHAOptions googlereCAPTCHAOptions = services.BuildServiceProvider().GetService <IOptionsSnapshot <GooglereCAPTCHAOptions> >().Value;

            if (googlereCAPTCHAOptions.Enabled)
            {
                services.AddreCAPTCHAV3(x =>
                {
                    x.VerifyBaseUrl = googlereCAPTCHAOptions.VerifyBaseUrl;
                    x.SiteKey       = googlereCAPTCHAOptions.SiteKey;
                    x.SiteSecret    = googlereCAPTCHAOptions.SiteSecret;
                });
            }

            services.AddDIServices(Configuration);

            services.AddSwaggerGenNewtonsoftSupport();
            //Swagger 扩展方法配置Swagger
            services.AddSwaggerGen();

            //应用程序级别设置
            services.Configure <FormOptions>(options =>
            {
                //单个文件上传的大小限制为8 MB      默认134217728 应该是128MB
                options.MultipartBodyLengthLimit = 1024 * 1024 * 8; //8MB
            });

            // 分布式事务一致性CAP
            services.AddCap(Configuration);

            services.Configure <ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
            });

            //之前请注入AddCsRedisCore,内部实现IDistributedCache接口
            services.AddIpRateLimiting(Configuration);

            services.AddHealthChecks();
        }
Example #9
0
        public async Task <UnifyResponseDto> DeleteMyComment(Guid id)
        {
            await _commentService.DeleteMyComment(id);

            return(UnifyResponseDto.Success());
        }
Example #10
0
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddContext(Configuration);
            services.AddCsRedisCore(Configuration);
            JsonWebTokenSettings jsonWebTokenSettings = services.AddSecurity(Configuration);

            #region AddJwtBearer
            services.AddAuthentication(opts =>
            {
                opts.DefaultScheme             = CookieAuthenticationDefaults.AuthenticationScheme;
                opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                bool isIds4 = Configuration["Service:IdentityServer4"].ToBoolean();

                if (isIds4)
                {
                    //identityserver4 地址 也就是本项目地址
                    options.Authority = Configuration["Service:Authority"];
                }
                options.RequireHttpsMetadata = Configuration["Service:UseHttps"].ToBoolean();
                options.Audience             = Configuration["Service:Name"];

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    // The signing key must match!
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = jsonWebTokenSettings.SecurityKey,

                    // Validate the JWT Issuer (iss) claim
                    ValidateIssuer = true,
                    ValidIssuer    = jsonWebTokenSettings.Issuer,

                    // Validate the JWT Audience (aud) claim
                    ValidateAudience = true,
                    ValidAudience    = jsonWebTokenSettings.Audience,

                    // Validate the token expiry
                    ValidateLifetime = true,

                    // If you want to allow a certain amount of clock drift, set thatValidIssuer  here
                    //ClockSkew = TimeSpan.Zero
                };

                //options.TokenValidationParameters = new TokenValidationParameters()
                //{
                //    ClockSkew = TimeSpan.Zero   //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟
                //};


                //使用Authorize设置为需要登录时,返回json格式数据。
                options.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = context =>
                    {
                        //Token expired
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }

                        return(Task.CompletedTask);
                    },
                    OnChallenge = context =>
                    {
                        //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦
                        context.HandleResponse();

                        string message;
                        ErrorCode errorCode;
                        int statusCode = StatusCodes.Status401Unauthorized;

                        if (context.Error == "invalid_token" &&
                            context.ErrorDescription == "The token is expired")
                        {
                            message    = "令牌过期";
                            errorCode  = ErrorCode.TokenExpired;
                            statusCode = StatusCodes.Status422UnprocessableEntity;
                        }
                        else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty())
                        {
                            message   = "令牌失效";
                            errorCode = ErrorCode.TokenInvalidation;
                        }
                        else
                        {
                            message   = "请先登录" + context.ErrorDescription;   //""认证失败,请检查请求头或者重新登录";
                            errorCode = ErrorCode.AuthenticationFailed;
                        }

                        context.Response.ContentType = "application/json";
                        context.Response.StatusCode  = statusCode;
                        context.Response.WriteAsync(new UnifyResponseDto(errorCode, message, context.HttpContext).ToString());

                        return(Task.FromResult(0));
                    }
                };
            })
            .AddGitHub(options =>
            {
                options.ClientId     = Configuration["Authentication:GitHub:ClientId"];
                options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"];
                options.Scope.Add("user:email");
                options.ClaimActions.MapJsonKey(LinConsts.Claims.AvatarUrl, "avatar_url");
                options.ClaimActions.MapJsonKey(LinConsts.Claims.HtmlUrl, "html_url");
                //登录成功后可通过  authenticateResult.Principal.FindFirst(ClaimTypes.Uri)?.Value;  得到GitHub头像
                options.ClaimActions.MapJsonKey(LinConsts.Claims.BIO, "bio");
                options.ClaimActions.MapJsonKey(LinConsts.Claims.BlogAddress, "blog");
            })
            .AddQQ(options =>
            {
                options.ClientId     = Configuration["Authentication:QQ:ClientId"];
                options.ClientSecret = Configuration["Authentication:QQ:ClientSecret"];
            })
            .AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, "码云", options =>
            {
                options.ClientId     = Configuration["Authentication:Gitee:ClientId"];
                options.ClientSecret = Configuration["Authentication:Gitee:ClientSecret"];

                options.ClaimActions.MapJsonKey("urn:gitee:avatar_url", "avatar_url");
                options.ClaimActions.MapJsonKey("urn:gitee:blog", "blog");
                options.ClaimActions.MapJsonKey("urn:gitee:bio", "bio");
                options.ClaimActions.MapJsonKey("urn:gitee:html_url", "html_url");
                //options.Scope.Add("projects");
                //options.Scope.Add("pull_requests");
                //options.Scope.Add("issues");
                //options.Scope.Add("notes");
                //options.Scope.Add("keys");
                //options.Scope.Add("hook");
                //options.Scope.Add("groups");
                //options.Scope.Add("gists");
                //options.Scope.Add("enterprises");

                options.SaveTokens = true;
            });

            #endregion

            services.AddAutoMapper(typeof(UserProfile).Assembly, typeof(PoemProfile).Assembly);

            services.AddCors();

            #region Mvc

            services.AddControllers(options =>
            {
                options.ValueProviderFactories.Add(new ValueProviderFactory()); //设置SnakeCase形式的QueryString参数
                //options.Filters.Add<LogActionFilterAttribute>(); // 添加请求方法时的日志记录过滤器
                options.Filters.Add <LinCmsExceptionFilter>();                  //
            })
            .AddNewtonsoftJson(opt =>
            {
                opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss";
                // 设置自定义时间戳格式
                opt.SerializerSettings.Converters = new List <JsonConverter>()
                {
                    new LinCmsTimeConverter()
                };
                // 设置下划线方式,首字母是小写
                opt.SerializerSettings.ContractResolver = new DefaultContractResolver()
                {
                    NamingStrategy = new SnakeCaseNamingStrategy()
                    {
                        //ProcessDictionaryKeys = true
                    },
                };
            })
            .ConfigureApiBehaviorOptions(options =>
            {
                //options.SuppressConsumesConstraintForFormFileParameters = true; //SuppressUseValidationProblemDetailsForInvalidModelStateResponses;
                //自定义 BadRequest 响应
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = new ValidationProblemDetails(context.ModelState);
                    var resultDto      = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext);

                    return(new BadRequestObjectResult(resultDto)
                    {
                        ContentTypes = { "application/json" }
                    });
                };
            });
            services.AddSwaggerGenNewtonsoftSupport();
            #endregion

            services.AddDIServices(Configuration);

            #region Swagger

            //Swagger重写PascalCase,改成SnakeCase模式
            services.TryAddEnumerable(ServiceDescriptor.Transient <IApiDescriptionProvider, ApiDescriptionProvider>());

            //Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(options =>
            {
                string ApiName = "LinCms.Web";
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title   = ApiName + RuntimeInformation.FrameworkDescription,
                    Version = "v1",
                    Contact = new OpenApiContact
                    {
                        Name  = ApiName,
                        Email = "*****@*****.**",
                        Url   = new Uri("https://www.cnblogs.com/igeekfan/")
                    },
                    License = new OpenApiLicense
                    {
                        Name = ApiName + " 官方文档",
                        Url  = new Uri("https://luoyunchong.github.io/vovo-docs/dotnetcore/lin-cms/dotnetcore-start.html")
                    }
                });

                var security = new OpenApiSecurityRequirement()
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference()
                            {
                                Id   = JwtBearerDefaults.AuthenticationScheme,
                                Type = ReferenceType.SecurityScheme
                            }
                        },
                        Array.Empty <string>()
                    }
                };
                options.AddSecurityRequirement(security); //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                    Name        = "Authorization",          //jwt默认的参数名称
                    In          = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = SecuritySchemeType.ApiKey
                });
                try
                {
                    string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml");
                    options.IncludeXmlComments(xmlPath, true);
                    //实体层的xml文件名
                    string xmlEntityPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(IEntity).Assembly.GetName().Name}.xml");
                    options.IncludeXmlComments(xmlEntityPath);
                    //Dto所在类库
                    string applicationPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(IApplicationService).Assembly.GetName().Name}.xml");
                    options.IncludeXmlComments(applicationPath);
                }
                catch (Exception ex)
                {
                    Log.Logger.Warning(ex.Message);
                }
            });

            #endregion


            //应用程序级别设置

            services.Configure <FormOptions>(options =>
            {
                //单个文件上传的大小限制为8 MB      默认134217728 应该是128MB
                options.MultipartBodyLengthLimit = 1024 * 1024 * 8; //8MB
            });

            // 分布式事务一致性CAP
            services.AddCap(Configuration);

            services.Configure <ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
            });

            //之前请注入AddCsRedisCore,内部实现IDistributedCache接口
            services.AddIpRateLimiting(Configuration);

            services.AddHealthChecks();
        }
Example #11
0
 public UnifyResponseDto Info()
 {
     return(UnifyResponseDto.Success("Lin 是一套基于 Python-Flask 的一整套开箱即用的后台管理系统(CMS)。Lin 遵循简洁、高效的原则,通过核心库加插件的方式来驱动整个系统高效的运行"));
 }
Example #12
0
        public async Task <IActionResult> SignInBindCallBack(string provider, string redirectUrl = "", string token = "")
        {
            if (string.IsNullOrWhiteSpace(provider))
            {
                return(BadRequest());
            }

            if (!await HttpContext.IsProviderSupportedAsync(provider))
            {
                return(BadRequest());
            }

            if (token.IsNullOrEmpty() || !token.StartsWith("Bearer "))
            {
                return(Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("请先登录")}"));
            }
            else
            {
                token = token.Remove(0, 7);
            }

            AuthenticateResult authenticateResult = await _contextAccessor.HttpContext.AuthenticateAsync(provider);

            if (!authenticateResult.Succeeded)
            {
                return(Redirect($"{redirectUrl}#bind-result?code=fail&message={authenticateResult.Failure.Message}"));
            }
            var openIdClaim = authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier);

            if (openIdClaim == null || string.IsNullOrWhiteSpace(openIdClaim.Value))
            {
                return(Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("未能获取openId")}"));
            }

            JwtPayload jwtPayload     = (JwtPayload)_jsonWebTokenService.Decode(token);
            string     nameIdentifier = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.NameIdentifier)?.Value;

            if (nameIdentifier.IsNullOrWhiteSpace())
            {
                return(Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("请先登录")}"));
            }
            long             userId = long.Parse(nameIdentifier);
            UnifyResponseDto unifyResponseDto;

            List <string> supportProviders = new List <string> {
                LinUserIdentity.Gitee, LinUserIdentity.GitHub, LinUserIdentity.QQ
            };

            if (!supportProviders.Contains(provider))
            {
                _logger.LogError($"未知的privoder:{provider},redirectUrl:{redirectUrl}");
                unifyResponseDto = UnifyResponseDto.Error($"未知的privoder:{provider}!");
            }
            else
            {
                IOAuth2Service oAuth2Service = _componentContext.ResolveNamed <IOAuth2Service>(provider);
                unifyResponseDto = await oAuth2Service.BindAsync(authenticateResult.Principal, provider, openIdClaim.Value, userId);
            }

            return(Redirect($"{redirectUrl}#bind-result?code={unifyResponseDto.Code.ToString()}&message={HttpUtility.UrlEncode(unifyResponseDto.Message.ToString())}"));
        }
 public UnifyResponseDto Logout()
 {
     return(UnifyResponseDto.Success("退出登录"));
 }
        public async Task <UnifyResponseDto> PutAsync(int id, [FromBody] CreateUpdateBookDto updateBook)
        {
            await _bookService.UpdateAsync(id, updateBook);

            return(UnifyResponseDto.Success("更新图书成功"));
        }
Example #15
0
        public void ConfigureServices(IServiceCollection services)
        {
            InMemoryConfiguration.Configuration = this.Configuration;

            services.AddContext();

            services.AddCors();

            services.ConfigureApplicationCookie(options =>
            {
                options.LoginPath = "/account/login";
            });
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromSeconds(120);
            });

            services.AddIdentityServer(options => new IdentityServerOptions
            {
                UserInteraction = new UserInteractionOptions
                {
                    LoginUrl  = "/account/login",
                    LogoutUrl = "/account/logout",
                }
            })
#if DEBUG
            .AddDeveloperSigningCredential()
#endif
#if !DEBUG
            .AddSigningCredential(new X509Certificate2(
                                      Path.Combine(AppContext.BaseDirectory, Configuration["Certificates:Path"]),
                                      Configuration["Certificates:Password"])
                                  )
#endif
            .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources())
            .AddInMemoryApiResources(InMemoryConfiguration.GetApis())
            .AddInMemoryClients(InMemoryConfiguration.GetClients())
            .AddInMemoryApiScopes(InMemoryConfiguration.GetApiScopes())
            .AddProfileService <LinCmsProfileService>()
            .AddResourceOwnerValidator <LinCmsResourceOwnerPasswordValidator>();

            #region Swagger

            //Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(options =>
            {
                string ApiName = "LinCms.IdentityServer4";
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title   = ApiName + RuntimeInformation.FrameworkDescription,
                    Version = "v1",
                    Contact = new OpenApiContact {
                        Name = ApiName, Email = "*****@*****.**", Url = new Uri("https://www.cnblogs.com/igeekfan/")
                    },
                    License = new OpenApiLicense {
                        Name = ApiName + " 官方文档", Url = new Uri("https://luoyunchong.github.io/vovo-docs/dotnetcore/lin-cms/dotnetcore-start.html")
                    }
                });
                var security = new OpenApiSecurityRequirement()
                {
                    { new OpenApiSecurityScheme
                      {
                          Reference = new OpenApiReference()
                          {
                              Id   = "Bearer",
                              Type = ReferenceType.SecurityScheme
                          }
                      }, Array.Empty <string>() }
                };
                options.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                    Name        = "Authorization",          //jwt默认的参数名称
                    In          = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
                    Type        = SecuritySchemeType.ApiKey
                });
                try
                {
                    string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml");
                    options.IncludeXmlComments(xmlPath, true);
                }
                catch (Exception ex)
                {
                    Log.Logger.Warning(ex.Message);
                }
                options.AddServer(new OpenApiServer()
                {
                    Url         = "",
                    Description = "vvv"
                });
                options.CustomOperationIds(apiDesc =>
                {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return(controllerAction.ControllerName + "-" + controllerAction.ActionName);
                });
            });
            #endregion

            services.AddTransient <IUserRepository, UserRepository>();
            services.AddTransient <IUserIdentityService, UserIdentityService>();
            services.AddTransient <ICurrentUser, CurrentUser>();
            services.AddTransient(typeof(IAuditBaseRepository <>), typeof(AuditBaseRepository <>));
            services.AddTransient(typeof(IAuditBaseRepository <,>), typeof(AuditBaseRepository <,>));
            //services.AddTransient<CustomExceptionMiddleWare>();

            services.AddAutoMapper(typeof(UserProfile).Assembly);

            services.AddControllersWithViews(options =>
            {
                options.Filters.Add <LinCmsExceptionFilter>();
            })
            .AddNewtonsoftJson(opt =>
            {
                //忽略循环引用
                opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss";
                //设置自定义时间戳格式
                opt.SerializerSettings.Converters = new List <JsonConverter>()
                {
                    new LinCmsTimeConverter()
                };
                // 设置下划线方式,首字母是小写
                //opt.SerializerSettings.ContractResolver = new DefaultContractResolver()
                //{
                //    NamingStrategy = new SnakeCaseNamingStrategy()
                //    {
                //        ProcessDictionaryKeys = true
                //    }
                //};
            })
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressConsumesConstraintForFormFileParameters = true;
                //自定义 BadRequest 响应
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = new ValidationProblemDetails(context.ModelState);

                    var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext);

                    return(new BadRequestObjectResult(resultDto)
                    {
                        ContentTypes = { "application/json" }
                    });
                };
            });
            services.AddHealthChecks();
        }
Example #16
0
        public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateCommentDto createCommentDto)
        {
            await _commentService.CreateAsync(createCommentDto);

            return(UnifyResponseDto.Success("评论成功"));
        }
Example #17
0
        public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateUpdateDocDto createDoc)
        {
            await _docService.CreateAsync(createDoc);

            return(UnifyResponseDto.Success("新增文档成功"));
        }
Example #18
0
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            Stopwatch.Stop();
            //当方法或控制器上存在DisableAuditingAttribute特性标签时,不记录日志
            if (context.ActionDescriptor is ControllerActionDescriptor d && d.MethodInfo.IsDefined(typeof(DisableAuditingAttribute), true) ||
                context.Controller.GetType().IsDefined(typeof(DisableAuditingAttribute), true)
                )
            {
                base.OnActionExecuted(context);
                return;
            }

            LinLog linLog = new LinLog()
            {
                Method       = context.HttpContext.Request.Method,
                Path         = context.HttpContext.Request.Path,
                StatusCode   = context.HttpContext.Response.StatusCode,
                OtherMessage = $"参数:{ActionArguments}\n耗时:{Stopwatch.Elapsed.TotalMilliseconds} 毫秒"
            };

            ControllerActionDescriptor auditActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;

            AuditingLogAttribute auditingLogAttribute = auditActionDescriptor.GetCustomAttribute <AuditingLogAttribute>();

            if (auditingLogAttribute != null)
            {
                linLog.Message = auditingLogAttribute.Template;
            }

            LinCmsAuthorizeAttribute linCmsAttribute = auditActionDescriptor.GetCustomAttribute <LinCmsAuthorizeAttribute>();

            if (linCmsAttribute != null)
            {
                linLog.Authority = linCmsAttribute.Permission;
            }


            base.OnActionExecuted(context);

            if (context.Result is ObjectResult objectResult && objectResult.Value != null)
            {
                if (objectResult.Value.ToString().Contains("ErrorCode"))
                {
                    UnifyResponseDto resultDto = JsonConvert.DeserializeObject <UnifyResponseDto>(objectResult.Value.ToString());

                    resultDto.Request = LinCmsUtils.GetRequest(context.HttpContext);

                    context.Result = new JsonResult(resultDto);

                    if (linLog.Message.IsNullOrEmpty())
                    {
                        linLog.Message = resultDto.Message?.ToString();
                    }
                }
            }

            linLog.Message += $"{_currentUser.UserName}访问{context.HttpContext.Request.Path},耗时:{Stopwatch.Elapsed.TotalMilliseconds} 毫秒";

            _logRepository.Create(linLog);

            //记录文本日志
            _logger.LogInformation(JsonConvert.SerializeObject(linLog));
        }
Example #19
0
        public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateUpdateTagDto createTag)
        {
            await _tagService.CreateAsync(createTag);

            return(UnifyResponseDto.Success("新建标签成功"));
        }
Example #20
0
        public async Task <UnifyResponseDto> Delete(Guid id)
        {
            await _articleService.DeleteAsync(id);

            return(UnifyResponseDto.Success());
        }
Example #21
0
        public async Task <UnifyResponseDto> CorrectedTagCountAsync(Guid tagId)
        {
            await _tagService.CorrectedTagCountAsync(tagId);

            return(UnifyResponseDto.Success());
        }
        public async Task <UnifyResponseDto> RemovePermissions(RemovePermissionDto permissionDto)
        {
            await _permissionService.DeletePermissionsAsync(permissionDto);

            return(UnifyResponseDto.Success("删除权限成功"));
        }
Example #23
0
        public async Task <UnifyResponseDto> DeleteAsync(long id)
        {
            await _resourceService.DeleteAsync(id);

            return(UnifyResponseDto.Success());
        }
        public async Task <UnifyResponseDto> CreateAsync([FromBody] CreateGroupDto inputDto)
        {
            await _groupService.CreateAsync(inputDto);

            return(UnifyResponseDto.Success("新建分组成功"));
        }
Example #25
0
        public async Task <UnifyResponseDto> UpdateAsync([FromBody] ResourceDto updateResource)
        {
            await _resourceService.UpdateAsync(updateResource);

            return(UnifyResponseDto.Success("更新成功"));
        }
        public async Task <UnifyResponseDto> UpdateAsync(long id, [FromBody] UpdateGroupDto updateGroupDto)
        {
            await _groupService.UpdateAsync(id, updateGroupDto);

            return(UnifyResponseDto.Success("更新分组成功"));
        }
        public async Task <UnifyResponseDto> DeleteAsync(int id)
        {
            await _baseTypeService.DeleteAsync(id);

            return(UnifyResponseDto.Success());
        }
        public async Task <UnifyResponseDto> DeleteAsync(long id)
        {
            await _groupService.DeleteAsync(id);

            return(UnifyResponseDto.Success("删除分组成功"));
        }
        public async Task <UnifyResponseDto> UpdateAsync(int id, [FromBody] CreateUpdateBaseTypeDto updateBaseType)
        {
            await _baseTypeService.UpdateAsync(id, updateBaseType);

            return(UnifyResponseDto.Success("更新类别成功"));
        }
        public async Task <UnifyResponseDto> ResetPasswordAsync(long id, [FromBody] ResetPasswordDto resetPasswordDto)
        {
            await _userSevice.ResetPasswordAsync(id, resetPasswordDto);

            return(UnifyResponseDto.Success("密码修改成功"));
        }