WebApi配置

WebApi配置

模版使用的是Ater.dry

1.Program配置

img

namespace WebApplication1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // 1 注册和配置Web服务依赖
            builder.AddDefaultWebServices();

            WebApplication app = builder.Build();

            // 2 使用中间件
            app.UseDefaultWebServices();

            app.Run();

        }
    }
}

2.ServiceCollectionExtension配置

img

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Net;
using System.Text;
using System.Threading.RateLimiting;

namespace WebApplication1
{
    public static class ServiceCollectionExtension
    {
        /// <summary>
        /// 注册和配置Web服务依赖
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IServiceCollection AddDefaultWebServices(this WebApplicationBuilder builder)
        {
            builder.Services.ConfigWebComponents(builder.Configuration);

            builder.Services.AddHttpContextAccessor();

            builder.Services.AddControllers()
                   .AddNewtonsoftJson(options =>
                   {
                       options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //忽略循环引用
                       options.SerializerSettings.ContractResolver = new DefaultContractResolver(); //使用默认的合同解析器
                       options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; //设置日期时间格式
                       //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;  //空值处理
                       options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local; // 处理日期时间的时区为本地时区
                       options.SerializerSettings.Converters.Add(new StringEnumConverter()); //枚举值转换为字符串
                   });

            return builder.Services;
        }

        #region 添加web服务组件,如身份认证/授权/swagger/cors
        /// <summary>
        /// 添加web服务组件,如身份认证/授权/swagger/cors
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection ConfigWebComponents(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddSwagger();
            services.AddJwtAuthentication(configuration);
            services.AddAuthorize();
            services.AddCors();
            services.AddRateLimiter();
            return services;
        }

        /// <summary>
        /// 添加swagger服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSwagger(this IServiceCollection services)
        {

            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen(c =>
            {
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,
                    Description = "Please enter a valid token",
                    Name = "Authorization",
                    Type = SecuritySchemeType.Http,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type=ReferenceType.SecurityScheme,
                            Id="Bearer"
                        }
                    },
                    Array.Empty<string>()
                }
            });
                c.SwaggerDoc("admin", new OpenApiInfo
                {
                    Title = "Demo1",
                    Description = "Admin API 文档. 更新时间:" + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss"),
                    Version = "v1"
                });
                c.SwaggerDoc("client", new OpenApiInfo
                {
                    Title = "Demo1 client",
                    Description = "Client API 文档. 更新时间:" + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss"),
                    Version = "v1"
                });
                var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml", SearchOption.TopDirectoryOnly);
                foreach (var item in xmlFiles)
                {
                    try
                    {
                        c.IncludeXmlComments(item, includeControllerXmlComments: true);
                    }
                    catch (Exception) { }
                }
                c.SupportNonNullableReferenceTypes();
                c.DescribeAllParametersInCamelCase();
                c.CustomOperationIds((z) =>
                {
                    var descriptor = (ControllerActionDescriptor)z.ActionDescriptor;
                    return $"{descriptor.ControllerName}_{descriptor.ActionName}";
                });
                c.MapType<DateOnly>(() => new OpenApiSchema
                {
                    Type = "string",
                    Format = "date"
                });
            });
            return services;
        }

        /// <summary>
        /// 添加 jwt 验证
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static IServiceCollection AddJwtAuthentication(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddAuthentication(options =>
            {
                // 设置默认的身份验证方案为 JWT Bearer
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            //等于builder.Services.AddAuthentication("Bearer")

            // 添加 JWT Bearer 身份验证方案配置
            .AddJwtBearer(cfg =>
            {
                cfg.SaveToken = true;

                // 从配置中获取 JWT 签名
                var sign = configuration.GetSection("Authentication")["Jwt:Sign"];
                if (string.IsNullOrEmpty(sign))
                {
                    throw new Exception("未找到有效的Jwt配置");
                }

                // 配置 Token 验证参数
                cfg.TokenValidationParameters = new()
                {
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(sign)),
                    ValidIssuer = configuration.GetSection("Authentication")["Jwt:ValidIssuer"],
                    ValidAudience = configuration.GetSection("Authentication")["Jwt:ValidAudiences"],
                    ValidateIssuer = true,
                    ValidateLifetime = true,
                    RequireExpirationTime = true,
                    ValidateIssuerSigningKey = true
                };
            });
            return services;
        }

        /// <summary>
        /// 添加 Authorize 服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddAuthorize(this IServiceCollection services)
        {
            services.AddAuthorizationBuilder()
                .AddPolicy("User", policy => policy.RequireRole("User"))
                .AddPolicy("AdminUser", policy => policy.RequireRole("SuperAdmin", "AdminUser"))
                .AddPolicy("SuperAdmin", policy => policy.RequireRole("SuperAdmin"));
            return services;
        }

        /// <summary>
        /// 添加Cros服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddCors(this IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("Default", builder =>
                {
                    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
                });
            });
            return services;
        }

        /// <summary>
        /// 添加速率限制
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddRateLimiter(this IServiceCollection services)
        {
            services.AddRateLimiter(options =>
            {
                options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
                // 验证码  每10秒5次
                options.AddPolicy("captcha", context =>
                {
                    var remoteIpAddress = context.Connection.RemoteIpAddress;
                    if (!IPAddress.IsLoopback(remoteIpAddress!))
                    {
                        return RateLimitPartition.GetFixedWindowLimiter(remoteIpAddress!.ToString(), _ =>
                        new FixedWindowRateLimiterOptions
                        {
                            PermitLimit = 5,
                            Window = TimeSpan.FromSeconds(10),
                            QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                            QueueLimit = 3
                        });
                    }
                    else
                    {
                        return RateLimitPartition.GetNoLimiter(remoteIpAddress!.ToString());
                    }
                });

                // 全局限制 每10秒100次
                options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, IPAddress>(context =>
                {
                    IPAddress? remoteIpAddress = context.Connection.RemoteIpAddress;

                    if (!IPAddress.IsLoopback(remoteIpAddress!))
                    {
                        return RateLimitPartition.GetFixedWindowLimiter(remoteIpAddress!, _ =>
                        new FixedWindowRateLimiterOptions
                        {
                            PermitLimit = 100,
                            Window = TimeSpan.FromSeconds(10),
                            QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                            QueueLimit = 3
                        });
                    }

                    return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);
                });
            });
            return services;
        }
        #endregion

        /// <summary>
        /// 使用中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static WebApplication UseDefaultWebServices(this WebApplication app)
        {
            // 异常统一处理
            // app.UseExceptionHandler(ExceptionHandler.Handler());
            if (app.Environment.IsDevelopment())
            {
                app.UseCors("Default");
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/client/swagger.json", name: "client");
                    c.SwaggerEndpoint("/swagger/admin/swagger.json", "admin");
                });
            }
            else
            {
                app.UseCors("Default");
                //app.UseHsts();
                app.UseHttpsRedirection();
            }

            app.UseRateLimiter();

            //添加默认页面
            DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();
            defaultFilesOptions.DefaultFileNames.Clear();
            defaultFilesOptions.DefaultFileNames.Add("index.html");
            app.UseDefaultFiles(defaultFilesOptions);

            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.MapControllers();

            return app;
        }

    }
}

3.统一异常处理

img

using Microsoft.AspNetCore.Diagnostics;

namespace WebApplication1
{
    public static class ExceptionHandler
    {
        public static Action<IApplicationBuilder> Handler()
        {
            return builder =>
            {
                builder.Run(async context =>
                {
                    context.Response.StatusCode = 500;
                    Exception? exception = context.Features.Get<IExceptionHandlerFeature>()?.Error;
                    var result = new
                    {
                        Title = "异常错误",
                        exception?.Source,
                        Detail = exception?.Message + exception?.InnerException?.Message,
                        exception?.StackTrace,
                        Status = 500,
                        TraceId = context.TraceIdentifier
                    };
                    await context.Response.WriteAsJsonAsync(result);
                });
            };
        }
    }
}

4.默认页面

img

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>默认页面</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 50px;
        }

        h1 {
            color: #333;
        }

        p {
            color: #666;
        }
    </style>
</head>
<body>
    <h1>这里是默认页面</h1>
</body>
</html>
posted @ 2024-04-22 11:32  好大的鱼  阅读(71)  评论(0)    收藏  举报