.Net6 Api Swagger配置

1、定义个Swagger版本(组)的枚举

cs 复制代码
namespace WebApp.Enums
{
    /// <summary>
    /// api版本枚举
    /// </summary>
    public enum ApiVersion
    {
        /// <summary>
        /// v1版本
        /// </summary>
        v1 = 1,
        /// <summary>
        /// v2版本
        /// </summary>
        v2 = 2,
    }
}

2、添加SwaggerExtentsion扩展类,配置注册Swagger

cs 复制代码
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Net.Http.Headers;
using System.Net;
using System.Reflection;
using System.Text;
using WebApp.Enums;

namespace WebApp.Common.Swagger
{
    /// <summary>
    /// SwaggerDoc配置
    /// 用法:在Program.cs文件中进行注册:builder.AddSwaggerGenExt();
    /// </summary>
    public static class SwaggerExtension
    {
        /// <summary>
        /// 扩展方法:Swagger文档
        /// </summary>
        /// <param name="services"></param>
        public static void AddSwaggerGenExt(this IServiceCollection services)
        {
            #region 添加Swagger
            //获取的是当前执行的方法所在的程序文件的名称:即项目名称,例如我的项目名称叫webapp 
            var AssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            services.AddSwaggerGen(options =>
            {
                #region 配置版本
                //options.SwaggerDoc("v1", new OpenApiInfo { Title = "售楼API", Version = "v1" });
                typeof(ApiVersion).GetEnumNames().ToList().ForEach(version =>
                {
                    options.SwaggerDoc(version, new OpenApiInfo()
                    {
                        Version = version,
                        Title = "凤凰网管理系统",
                        Description = $"凤凰网接口服务    版本: {version}",
                        Contact = new OpenApiContact
                        {
                            Name = "潇湘夜雨",
                            Email = "123@qq.com"
                        }
                    });
                });

                #endregion
                #region 配置注释文档

                // 获取当前项目的 XML文档文件路径:比如我的项目名称叫WebApp,那么它默认的 XML文档文件路径就是当前项目下的 WebApp.xml
                var xmlFile = $"{AssemblyName}.xml";
                var xmlFileFullPath = Path.Combine(AppContext.BaseDirectory, xmlFile);

                //var domainXmlPath = Path.Combine(AppContext.BaseDirectory, "Bgy.Domain.xml");      // 获取Bgy.Domain.xml文件路径
                //var viewmodelXmlPath = Path.Combine(AppContext.BaseDirectory, "Bgy.ViewModel.xml");// 获取Bgy.ViewModel.xml文件路径

                options.IncludeXmlComments(xmlFileFullPath, true); // 添加控制器层注释,true表示显示控制器注释

                //options.IncludeXmlComments(domainXmlPath);       // 添加Domain层注释
                //options.IncludeXmlComments(viewmodelXmlPath);    // 添加ViewModel层注释

                //对action的名称进行排序。
                options.OrderActionsBy(o => o.RelativePath);

                #endregion

                #region 配置授权认证信息

                //添加一个必须的全局安全信息,
                //第一个参数是方案唯一名称:和AddSecurityDefinition方法指定的方案名称标识一致即可:BearerAuth
                //第二个参数是方案的描述:可以是BasicAuthScheme、ApiKeyScheme的实例或OAuth2Scheme
                options.AddSecurityDefinition("BearerAuth", new OpenApiSecurityScheme()
                {
                    Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
                    Name = "Authorization",
                    In = ParameterLocation.Header, //配置jwt默认加在Authorization信息的位置:这里配置的是将jwt信息放在请求头Header中            
                    Type = SecuritySchemeType.Http,//使用Authorize头部                  
                    Scheme = "bearer", //内容为以 bearer开头
                    BearerFormat = "JWT",
                    //Reference= new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" }
                });

                //注册全局认证(所有的接口都可以使用认证)
                options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "BearerAuth" //方案名称标识
                            }
                        },
                        new string[] {} //不设权限
                    }
                });

                #endregion

                #region 在Swagger中扩展文件上传按钮
                options.OperationFilter<FileUploadFilter>();
                #endregion
            });
            #endregion
        }

        /// <summary>
        /// 扩展方法:配置SwaggerUI
        /// 用法:在Program.cs文件中进行注册:app.UseSwaggerUIExt();
        /// </summary>
        /// <param name="app"></param>
        public static void UseSwaggerUIExt(this WebApplication app)
        {
            //SwaggerBasicAuthMiddleware:是我自己扩展的一个中间件:目的是需要登陆才能到达Swagger的Index页面中,否则无法进入:可以根据需要去掉这个
            //需要安装:Swashbuckle.AspNetCore包
            //app.UseMiddleware<SwaggerBasicAuthMiddleware>();

            if (app.Environment.IsDevelopment())
            {
                //app.UseSwagger();
                //app.UseSwaggerUI();
            }

            var enviroment = app.Configuration["Swagger:environmentVariables"];
            switch (enviroment)
            {
                case "development":
                    app.UseSwagger();//启用Swagger中间件

                    app.UseSwaggerUI(options =>  //配置版本
                    {
                        typeof(ApiVersion).GetEnumNames().ToList().ForEach(version =>
                        {
                            options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
                        });

                    });

                    break;
                case "testing":
                    app.UseSwagger();
                    app.UseSwaggerUI(options =>
                    {
                        typeof(ApiVersion).GetEnumNames().ToList().ForEach(version =>
                        {
                            options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
                        });
                    });
                    break;
                case "production":
                    break;

            }
        }
    }

    #region 扩展功能
    /// <summary>
    /// 文件上传的扩展:实现在Swagger中上传文件的功能
    /// </summary>
    public class FileUploadFilter : IOperationFilter
    {
        /// <summary>
        /// 文件上传筛选:只有上传文件的方法才添加此功能
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="context"></param>
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            const string FileUploadContentType = "multipart/form-data";
            if (operation.RequestBody == null || !operation.RequestBody.Content.Any(x => x.Key.Equals(FileUploadContentType, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }
            if (context.ApiDescription.ParameterDescriptions[0].Type == typeof(IFormCollection))
            {
                operation.RequestBody = new OpenApiRequestBody
                {
                    Description = "文件上传",
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        {
                            FileUploadContentType,new OpenApiMediaType
                            {
                                Schema=new OpenApiSchema
                                {
                                    Type="object",
                                    Required=new HashSet<string>{ "file"},
                                    Properties=new Dictionary<string, OpenApiSchema>
                                    {
                                        {
                                            "file",new OpenApiSchema
                                            {
                                                Type="string",
                                                Format="binary"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                };
            }
        }
    }

    /// <summary>
    /// 如何在ASP.Net Core的生产环境中保护swagger ui,也就是index.html页面。其实swagger是自带禁用的功能的,只需要设置开关即可。
    /// 但是有一些场景,是需要把这些接口进行开放或者导出成文档供第三方进行调用,这个时候却又不想让所有人访问。
    /// 这里介绍一种权限控制访问的方式,用来指定用户使用;
    /// </summary>
    public class SwaggerBasicAuthMiddleware
    {
        private readonly RequestDelegate next;
        /// <summary>
        /// 增加对swagger ui的验证
        /// </summary>
        /// <param name="next"></param>
        public SwaggerBasicAuthMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
        /// <summary>
        /// 登陆功能实现
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext context)
        {
            if (context.Request.Path.StartsWithSegments("/swagger"))
            {
                string authHeader = context.Request.Headers["Authorization"];
                if (authHeader != null && authHeader.StartsWith("Basic "))
                {
                    // Get the credentials from request header
                    var header = AuthenticationHeaderValue.Parse(authHeader);
                    var inBytes = Convert.FromBase64String(header.Parameter);
                    var credentials = Encoding.UTF8.GetString(inBytes).Split(':');
                    var username = credentials[0];
                    var password = credentials[1];

                    //用户身份认证
                    if (username.Equals("admin") && password.Equals("123456"))
                    {
                        await next.Invoke(context).ConfigureAwait(false);
                        return;
                    }
                }
                context.Response.Headers["WWW-Authenticate"] = "Basic";
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            }
            else
            {
                await next.Invoke(context).ConfigureAwait(false);
            }
        }
    }
    #endregion
}

3、appsettings.json配置文件

javascript 复制代码
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Swagger": {
    "environmentVariables": "development" //:development  :testing  :production
  }
}

4、在Program.cs中注册SwaggerDoc及启用SwaggerUI

cs 复制代码
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using WebApp.Common.Swagger;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();


#region JWT鉴权授权
var audience = "Audience";
var issuer = "Issuer";
var securityKey = "SIGfMA0FCSqGSIb3DFEBAQUAA4GNADCBiQKBgQDI2a2EJ7d872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI593nNDAPfnJsas96mSA9Q/mD8RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)  //默认授权机制名称;                                      
         .AddJwtBearer(options =>
         {
             options.TokenValidationParameters = new TokenValidationParameters
             {
                 ValidateIssuer = true,//是否验证Issuer
                 ValidateAudience = true,//是否验证Audience
                 ValidateLifetime = true,//是否验证失效时间
                 ValidateIssuerSigningKey = true,//是否验证SecurityKey
                 ValidAudience = audience,//Audience
                 ValidIssuer = issuer,//Issuer,这两项和前面签发jwt的设置一致  表示谁签发的Token
                 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey))//拿到SecurityKey
             };
         });
#endregion


builder.Services.AddSwaggerGenExt();//SwaggerGen

var app = builder.Build();

app.UseSwaggerUIExt(); //SwaggerUI

app.UseAuthentication();

app.UseAuthorization();

app.MapControllers();

app.Run();

5、Api接口中使用

在接口控制器,或者方法上添加版本(组)标识:[ApiExplorerSettings(GroupName = "v1")]

cs 复制代码
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using WebApp.Enums;

namespace WebApp.Controllers
{
    /// <summary>
    /// 测试接口
    /// </summary>
    [ApiController]//[ApiController]能够推断参数的绑定源,就不需要[FromBody][FromForm][FromHeader][FromQuery][FromRoute]....来主动指定接收参数的形式
    [Route("api/[controller]/[action]")]
  
    public class HomeController : ControllerBase
    {
        private readonly ILogger<HomeController> _logger;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger"></param>
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }


        /// <summary>
        /// 查询案列1
        /// </summary>
        /// <param name="id">编号</param>
        /// <returns></returns>
        [HttpGet("Abc")] //url地址是:api/WeatherForecast/Get/Abc
        [ApiExplorerSettings(GroupName = "v1")]
        [Authorize]
        public IActionResult Get(int id)
        {
            return Ok(id);

            //返回值:IActionResult

            //return NotFound(); 404

            //return Redirect("/Home/Index");

            //var content = "Hello, World!";
            //return Content(content, "text/plain");

            //var data = new { Name = "John", Age = 30 };
            //return Json(data);

            //var filePath = "/path/to/file.pdf";
            //return File(filePath, "application/pdf", "filename.pdf");

            //byte[] videoBytes = System.IO.File.ReadAllBytes(containerPath);
            //return File(videoBytes, "video/mp4");
        }

        /// <summary>
        /// 查询案列2:路由的伪静态
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet("Abc/{name}")] //url地址是:api/WeatherForecast/Get/Abc/lily   :lily是name值, 同时name值是必填的,{name}必须要与action的参数名称一致。这就是路由的伪静态形式
        [ApiExplorerSettings(GroupName = nameof(ApiVersion.v1))]
        [Authorize]
        public IActionResult Get(string name)
        {
            return Ok(name);
        }


        /// <summary>
        /// 客户端登陆
        /// </summary>
        /// <param name="clientid">客户端名称</param>
        /// <param name="password">客户端密码</param>
        /// <returns>返回jwtToken</returns>
        [HttpGet]
        [ApiExplorerSettings(GroupName = nameof(ApiVersion.v2))]
        [Route("api/login")]
        public IActionResult Login(string clientid, string password)
        {
            //这里肯定是需要去连接数据库做数据校验
            if (clientid == "admin" && password == "123456")//应该数据库
            {
                string token = GetJwtToken(clientid);
                return Ok(new { token });
            }
            else
            {
                return Ok("");
            }
        }

        /// <summary>
        /// 获取Token
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        [NonAction]
        public string GetJwtToken(string UserName)
        {
            var issuer = "Issuer";
            var audience = "Audience";

            var securityKey = "SIGfMA0FCSqGSIb3DFEBAQUAA4GNADCBiQKBgQDI2a2EJ7d872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI593nNDAPfnJsas96mSA9Q/mD8RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";

            Claim[] claims = new[]
            {
               new Claim(ClaimTypes.Name, UserName)
            };
            SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(securityKey));
            SigningCredentials creds = new(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: issuer,
                audience: audience,
                claims: claims,
                expires: DateTime.Now.AddMinutes(1),//5分钟有效期
                signingCredentials: creds);
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        /// <summary>
        /// 文件上传
        /// </summary>
        /// <param name="from"></param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult UploadFile(IFormCollection from)
        {
            return new JsonResult(new
            {
                Success = true,
                Message = "上传成功",
                FileName = from.Files.FirstOrDefault()?.FileName

            }) ;     
        }


        /// <summary>
        /// 标记了[NonAction]特性,则不被视为控制器的操作方法
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost(Name = "{id}")]
        [NonAction]
        public string PostTest(int id)
        {
            return id.ToString();
        }
    }
}

6、项目配置生成XML文件

7、效果图

7、注意点:

如果只是单纯只返回token的时候,记得在控制器右上角的Authorize里 先写Bearer+空格+你的token

相关推荐
Kika写代码12 分钟前
【微信小程序】页面跳转基础 | 我的咖啡店-综合实训
服务器·微信小程序·小程序
m0_7482550221 分钟前
前端常用算法集合
前端·算法
真的很上进35 分钟前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web1309332039841 分钟前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
VinciYan1 小时前
基于Jenkins+Docker的自动化部署实践——整合Git与Python脚本实现远程部署
python·ubuntu·docker·自动化·jenkins·.net·运维开发
州周1 小时前
Ftp目录整个下载
linux·服务器·数据库
码农君莫笑1 小时前
使用blazor开发信息管理系统的应用场景
数据库·信息可视化·c#·.net·visual studio
NiNg_1_2341 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
冷曦_sole1 小时前
linux-19 根文件系统(一)
linux·运维·服务器
AI大模型学徒1 小时前
Linux(二)_清理空间
linux·运维·服务器