【Core Swagger】.NET Core中使用swagger

 一.入門

 https://www.nuget.org/packages/Swashbuckle.AspNetCore.SwaggerGen/

 

1.添加核心NUGET包 Swashbuckle.AspNetCore

 

2.startup中配置:

ConfigureServices中:

           //註冊swagger生成器,定義一個或多個swagger文檔
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info
                {
                    Version = "v1",
                    Title = "測試 API",
                    Description = "A simple example ASP.NET Core Web API",
                    TermsOfService = "None",
                    Contact = new Contact { Name = "ck", Email = "", Url = "http://www.cnblogs.com/chuankang/" },
                    License = new License { Name = "博客園", Url = "http://www.cnblogs.com/chuankang/" }
                });

                // api描述文檔xml的生成地址和文件名,需要在項目的屬性中進行配置
                var basePath = AppContext.BaseDirectory;
                var xmlPath = Path.Combine(basePath, "SwaggerDemo.xml");
                if (File.Exists(xmlPath))
                {
                    c.IncludeXmlComments(xmlPath);
                }
            });

 

Configure中:

        // 啓用中間件以生成JSON作爲JSON端點.
            app.UseSwagger();

            // 啓用中間件以提供用戶界面(HTML、js、CSS等),特別是指定JSON端點。
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
           //頁面頭名稱
                c.DocumentTitle = "平臺API";
             //頁面API文檔格式 Full=全部展開, List=只展開列表, None=都不展開
                c.DocExpansion(DocExpansion.List);
            }); 

 注意:c.SwaggerDoc的第一個參數 要和 c.SwaggerEndpoint第一個參數 字符串swagger/後面的對應,本例用的是v1

 

3.api描述文檔xml的生成地址和文件名,需要在項目的屬性中進行配置,右鍵項目-> 屬性-> 生成 如下圖:

加上1591忽略屬性類名必須加xml註釋

 

 

 

4.在controller中action方法都要指定http請求Post(新增),Put(修改),Delete(刪除),Get(查詢)中的一個,不然會報錯:
http://localhost:55642/swagger/v1/swagger.json   瀏覽器F12控制檯查看錯誤原因

 


 

 

 

5.啓動看效果:

 

6.每次輸入/swagger太麻煩,可以設置藉助vs進行跳轉,如下圖加上 "launchUrl": "swagger" :

 

 

7.如果controller繼承了自己定義的基類controller,要爲自己定義的方法加上NonActionFillter,因爲swagger要爲每個action添加http mehod

 

 二.設置多個API版本

ConfigureServices中: 
c.SwaggerDoc("v2", new Info { Version = "v2", Title = "API 版本2" });
Configure中: c.SwaggerEndpoint(
"/swagger/v2/swagger.json", "API V2");

 

在action上指定版本,不指定版本的action在所有版本中都顯示

 

 三.修改默認路由

swagger給我們默認的路由是:http://localhost:49833/swagger/index.html

如果有很多個API項目怎麼區分呢?我們可以指定路由把swagger替換掉

那麼我們現在應該請求的路由爲:http://localhost:49833/test/index.html

 

 四.忽略過時的接口

爲action指定Obsolete特性表示過時了,但並不表示不可以使用

運行:

怎麼把這過時的接口不顯示在swagger頁面呢?

 只需要在生成器中加入options.IgnoreObsoleteActions();屬性就行了

 

 五.忽略某個Api,不在ui頁面中顯示

 

 六.僅獲取某個Http請求的action

例如下面只獲取HttpGet請求的接口顯示在界面上

// ApiExplorerGetsOnlyConvention.cs
public class ApiExplorerGetsOnlyConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        action.ApiExplorer.IsVisible = action.Attributes.OfType<HttpGetAttribute>().Any();
    }
}

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(c =>
        c.Conventions.Add(new ApiExplorerGetsOnlyConvention())
    );

    ...
}

 

 七.對action根據Http請求進行分組

services.AddSwaggerGen(c =>
{
    ...
    c.TagActionsBy(api => api.HttpMethod);
};

 

 八.指定接口排序規則

services.AddSwaggerGen(c =>
{
    ...
    c.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.HttpMethod}");
};

 

 九.安裝並啓用註釋

安裝nuget Swashbuckle.AspNetCore.Annotations

啓用:

services.AddSwaggerGen(c =>
{
   ...

   c.EnableAnnotations();
});

 爲controller加註釋

 

 

 爲action加註釋

[HttpPost]

[SwaggerOperation(
    Summary = "Creates a new product",
    Description = "Requires admin privileges",
    OperationId = "CreateProduct",
    Tags = new[] { "Purchase", "Products" }
)]
public IActionResult Create([FromBody]Product product)

 

 

爲響應加驗證

[HttpPost]
[SwaggerResponse(201, "The product was created", typeof(Product))]
[SwaggerResponse(400, "The product data is invalid")]
public IActionResult Create([FromBody]Product product)

 

 十.Token驗證

ConfigureServices添加

 public void ConfigureServices(IServiceCollection services)
        {
            #region swagger
            services.AddSwaggerGen(c =>
            {
                //啓用註釋nuget包
                c.EnableAnnotations();
                c.SwaggerDoc("WebApiA", new Info { Title = "用戶API接口A", Version = "v1" });
                //var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                string basePath = AppContext.BaseDirectory;//Linux路徑區分大小寫,這裏用appcontext
                string xmlPath = Path.Combine(basePath, "WebApiA.xml");
                //如果有xml註釋文檔就讀取,需在項目屬性生成xml
                if (File.Exists(xmlPath))
                {
                    c.IncludeXmlComments(xmlPath);
                }

                #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授權(數據將在請求頭中進行傳輸) 直接在下框中輸入{token}\"",
                    Name = "Authorization",//jwt默認的參數名稱
                    In = "header",//jwt默認存放Authorization信息的位置(請求頭中)
                    Type = "apiKey"
                });
                #endregion
            });
            #endregion

            #region Token服務註冊
            services.AddSingleton<IMemoryCache>(factory =>
            {
                var cache = new MemoryCache(new MemoryCacheOptions());
                return cache;
            });
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
                options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
                options.AddPolicy("AdminOrClient", policy => policy.RequireRole("Admin,Client").Build());
            });
            #endregion


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

 

啓動:

 

每次請求時,從Header報文中,獲取密鑰token,這裏根據token可以進一步判斷相應的權限等

 

添加類

 

JwtHelper:

using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebApiA.Models;

namespace WebApiA.AuthHelper
{
    /// <summary>
    /// JWT序列化和反序列化
    /// </summary>
    public class JwtHelper
    {
        public static string SecretKey { get; set; } = "sdfsdfsrty45634kkhllghtdgdfss345t678fs";
        /// <summary>
        /// 頒發JWT字符串 
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJWT(TokenModelJWT tokenModel)
        {
            var dateTime = DateTime.UtcNow;
            var claims = new Claim[]
            {
                new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Uid.ToString()),//Id
                new Claim("Role", tokenModel.Role),//角色
                new Claim(JwtRegisteredClaimNames.Iat,dateTime.ToString(),ClaimValueTypes.Integer64)
            };
            //祕鑰
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtHelper.SecretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: "Blog.Core",
                claims: claims, //聲明集合
                expires: dateTime.AddHours(2),
                signingCredentials: creds);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

        /// <summary>
        /// 解析
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static TokenModelJWT SerializeJWT(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            object role = new object(); ;
            try
            {
                jwtToken.Payload.TryGetValue("Role", out role);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new TokenModelJWT
            {
                Uid = Convert.ToInt32(jwtToken.Id),
                Role = role != null ? role.ToString() : "",
            };
            return tm;
        }
    }
}
View Code

 

 JwtTokenAuth:

/// <summary>
    /// 中間件
    /// </summary>
    public class JwtTokenAuth
    {
        private readonly RequestDelegate _next;
        public JwtTokenAuth(RequestDelegate next)
        {
            _next = next;
        }

        public Task Invoke(HttpContext httpContext)
        {
            //檢測是否包含'Authorization'請求頭
            if (!httpContext.Request.Headers.ContainsKey("Authorization"))
            {
                return _next(httpContext);
            }
            var tokenHeader = httpContext.Request.Headers["Authorization"].ToString();

            TokenModelJWT tm = JwtHelper.SerializeJWT(tokenHeader);//序列化token,獲取授權

            //授權 注意這個可以添加多個角色聲明,請注意這是一個 list
            var claimList = new List<Claim>();
            var claim = new Claim(ClaimTypes.Role, tm.Role);
            claimList.Add(claim);
            var identity = new ClaimsIdentity(claimList);
            var principal = new ClaimsPrincipal(identity);
            httpContext.User = principal;

            return _next(httpContext);
        }
    }
View Code

 

startup的Configure中加入

//將TokenAuth註冊中間件
app.UseMiddleware<JwtTokenAuth>();

 

 

接口加權限filter

 

啓動調用會報錯

 

 是因爲每次操作請求,都會經過TokenAuth 中的Invoke方法,方法中對Header信息進行過濾,因爲現在Header中,並沒有相應的配置信息,看到這裏,你就想到了,這個特別像我們常見的[HttpGet]等特性,沒錯!在.Net Core 中,到處都可以看到AOP編程,真的特別強大。

這個時候我們就用到了最開始的那個權限按鈕

 

 

新建一個LoginController,來模擬一次登陸操作,簡單傳遞幾個參數,將用戶角色和緩存時間傳遞,然後生成Token,並生成到緩存中,爲之後做準備。

 [Route("api/[controller]")]
    public class LoginController : Controller
    {
        /// <summary>
        /// 獲取JWT的重寫方法,推薦這種,注意在文件夾OverWrite下
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="sub">角色</param>
        /// <returns></returns>
        [HttpGet]
        [Route("Token2")]
        public JsonResult GetJWTStr(long id = 1, string sub = "Admin")
        {
            //這裏就是用戶登陸以後,通過數據庫去調取數據,分配權限的操作
            TokenModelJWT tokenModel = new TokenModelJWT();
            tokenModel.Uid = id;
            tokenModel.Role = sub;

            string jwtStr = JwtHelper.IssueJWT(tokenModel);
            return Json(jwtStr);
        }
    }

 

調用獲取tonken

 

複製到這裏驗證:

 

再次調用接口就可以了

 

 示例代碼:https://github.com/chuankang/DotNetCore/tree/master/OwnSpace/WebApiA

 

 參考文檔:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/web-api-help-pages-using-swagger

                  https://github.com/domaindrivendev/Swashbuckle.AspNetCore

隱藏相關接口 

對於不想暴漏給Swagger展示的接口,我們可以給相關Controller或Action頭加上:[ApiExplorerSettings(IgnoreApi = true)]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章