• NETCore2.2/3.0+使用带有权限验证的Swagger


    Swagger

    什么是Swagger

    Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。方便前后端接口对接。
    NetCore使用Swagger官方文档

    NuGet安装

    打开NuGet程序包,搜索“Swashbuckle.AspNetCore”安装。
    注意:NETCore3.0版本需要使用Swashbuckle.AspNetCore5.0以上的版本,搜索“Swashbuckle.AspNetCore”。我这个用的是NETCore2.2。
    在这里插入图片描述

    Startup注册Swagger

    在Startup的ConfigureServices方法中注册Swagger服务。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
        #region Swagger
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info
            {
                Version = "v0.1.0",//版本号
                Title = "ZZTApi文档",//文档标题
                Description = "框架说明文档",//文档描述
                TermsOfService = "None",//服务条款
                Contact = new Contact { Name = "zzt", Email = "000000@qq.com", Url = "www.baidu.com" }//联系人
            });       
        });
        #endregion
        #region Swagger NetCore3.0以上用这个
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Version = "v0.1.0",//版本号
                Title = "ZZTApi文档",//文档标题
                Description = "框架说明文档",//文档描述
                TermsOfService = new Uri("https://example.com/terms"),//服务条款
                Contact = new OpenApiContact { Name = "zzt", Email = "000000@qq.com", Url = new Uri("https://blog.csdn.net/zt102545") }//联系人
            });
            //简单写法:c.SwaggerDoc("v1", new OpenApiInfo { Title = "Web API", Version = "v1" });
    	    var xmlAPIPath = Path.Combine(basePath, "ZZTCoreAPI.xml");//这个就是刚刚配置的xml文件名
    	    var xmlModelPath = Path.Combine(basePath, "ZZTCoreModel.xml");//这个是引用model层的XML文档。设置输出XML文档的方法跟上面的一样。
    	    c.IncludeXmlComments(xmlAPIPath, true);//第二个参数true表示用控制器的XML注释。默认是false
    	    c.IncludeXmlComments(xmlModelPath, true);
        });
        #endregion
    }
    

    在Startup的Configure方法里面调用Swagger服务

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseMvc();
       
        #region Swagger;NetCore3.0以上版本写法一样
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
        });
        #endregion
    }
    

    保存后按F5调试,浏览器地址访问http://localhost:51146/swagger/index.html(每个人端口号可能不一样)。
    在这里插入图片描述

    设置默认首页打开Swagger

    如果不想每次访问都要输入/swagger/index.html来使用Swagger,希望根目录就是Swagger界面。可以这样设置:

    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
        c.RoutePrefix = "";//路径配置,设置为空,表示直接访问该文件。
    });
    

    有可能每次运行都会默认访问http://localhost:51146/api/values这个路径下的地址。需要在launchSettings.json文件下修改。
    在这里插入图片描述

    为接口添加注释

    如图,文档里面我们需要在红框里面为接口添加注释,以方便理解每个接口的功能。
    在这里插入图片描述
    右键项目名称=>属性=>生成,勾选“输出”下面的“xml文档文件”,系统会默认生成一个,你也可以自定义。
    这里我用的是相对路径。添加取消警告代码1590。否则会有一些警告。
    在这里插入图片描述
    在接口方法上边添加注释,说明每个接口的功能。
    在这里插入图片描述
    最后在services.AddSwaggerGen里面添加XML文档的路径。

    #region Swagger
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info
        {
            Version = "v0.1.0",
            Title = "ZZTApi文档",
            Description = "框架说明文档",
            TermsOfService = "None",
            Contact = new Contact { Name = "zzt", Email = "529166258@qq.com", Url = "www.baidu.com" }
        });
    
        #region 为 Swagger JSON and UI设置xml文档注释路径
        var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
        var xmlAPIPath = Path.Combine(basePath, "ZZTCoreAPI.xml");//这个就是刚刚配置的xml文件名
        var xmlModelPath = Path.Combine(basePath, "ZZTCoreModel.xml");//这个是引用model层的XML文档。设置输出XML文档的方法跟上面的一样。
        c.IncludeXmlComments(xmlAPIPath, true);//第二个参数true表示用控制器的XML注释。默认是false
        c.IncludeXmlComments(xmlModelPath, true);
        #endregion
    });
    
    

    以上代码还添加了一个model层的XML文档。设置方法是一样的。它的效果可以看以下几张图。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    以上就是Swagger一些简单应用

    JWT

    什么是JWT

    JWT,即JSON Web Tokens,是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。它是一种用于双方之间传递安全信息的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的、自包含的方法,从而使通信双方实现以JSON对象的形式安全的传递信息。

    注册授权认证服务

    在Startup的ConfigureServices方法里面添加以下代码

    #region JWT
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["Audience:Secret"])); 
    services.AddAuthentication("Bearer").AddJwtBearer(o=> {
        o.TokenValidationParameters = new TokenValidationParameters
        {
            //是否开启密钥认证和key值
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = signingKey,
    
            //是否开启发行人认证和发行人
            ValidateIssuer = true,
            ValidIssuer = Configuration["Audience:Issuer"],
    
            //是否开启订阅人认证和订阅人
            ValidateAudience = true,
            ValidAudience = Configuration["Audience:Audience"],
    
            //认证时间的偏移量
            ClockSkew = TimeSpan.Zero,
            //是否开启时间认证
            ValidateLifetime = true,
            //是否该令牌必须带有过期时间
            RequireExpirationTime = true
        };
    });
    #endregion
    

    其中Configuration[“Audience:xxx”]是读取appsettings.json配置文件里面的一些参数,参数如下:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "Audience": {
        "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs",
        "Issuer": "ZZT",
        "Audience": "Nobody"
      }
    }
    

    注册后需要在Configure方法里面加入代码app.UseAuthentication();来开启服务

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        //HTTP管道是有先后顺序的,一定要写在 app.Mvc() 之前,否则不起作用。
        app.UseAuthentication();
        app.UseMvc();
       
        #region Swagger
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
            c.RoutePrefix = "";//路径配置,设置为空,表示直接访问该文件,
        });
        #endregion
    }
    

    API接口添加授权策略

    在接口方法上边加入Authorize特性,表示该接口需要进行授权认证。
    带上Roles参数表示是基于角色的策略
    在这里插入图片描述
    如果有多个角色授权的话,在Startup的ConfigureServices方法中加入以下代码

    // 【授权】,好处就是不用在controller中,写多个 roles 。
    // 然后接口授权这么写 [Authorize(Policy = "Admin")]
    services.AddAuthorization(options =>
    {
        options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
        options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
        options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
    });
    

    获取JWT的Token

    以下代码是获取JWTToken的方法,作用是传入一个model,生成Token,这个model可以根据需求自己定义,涉及主要的两个对象JwtSecurityTokenJwtSecurityTokenHandler

    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Security.Claims;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ZZTCoreAPI.Common
    {
        public class JwtHelper
        {
            public static string IssueJWT(TokenModelJWT tokenModel)
            {
                var dateTime = DateTime.UtcNow;
                string iss = Appsettings.GetConfigure("Audience:Issuer");
                string aud = Appsettings.GetConfigure("Audience:Audience");
                string secret = Appsettings.GetConfigure("Audience:Secret");
    
                //var claims = new Claim[] //old
                var claims = new List<Claim>
                    {
                        //下边为Claim的默认配置
                    new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    //这个就是过期时间,目前是过期100秒,可自定义,注意JWT有自己的缓冲过期时间
                    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(100)).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Iss,iss),
                    new Claim(JwtRegisteredClaimNames.Aud,aud),
                    
                    //new Claim(ClaimTypes.Role,tokenModel.Role),//为了解决一个用户多个角色(比如:Admin,System),用下边的方法
                   };
    
                // 可以将一个用户的多个角色全部赋予;
                // 作者:DX 提供技术支持;
                claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
    
    
                //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var jwt = new JwtSecurityToken(
                    issuer: iss,
                    claims: claims,
                    signingCredentials: creds);
    
                var jwtHandler = new JwtSecurityTokenHandler();
                var encodedJwt = jwtHandler.WriteToken(jwt);
    
                return encodedJwt;
            }
    
        }
        /// <summary>
        /// 令牌
        /// </summary>
        public class TokenModelJWT
        {
            /// <summary>
            /// Id
            /// </summary>
            public long Uid { get; set; }
            /// <summary>
            /// 角色
            /// </summary>
            public string Role { get; set; }
            /// <summary>
            /// 职能
            /// </summary>
            public string Work { get; set; }
    
        }
    }
    
    

    以下代码是获取Token的接口,作用是根据传入的账号密码生成一个model传入以下代码中的IssueJWT方法以获取Token返回给前端。前端在 Http 的 Header 里,增加属性Authorization,并把这个Token带上Bearer 即Bearer {Token}这个值赋给Authorization属性作为访问其他接口的授权校验。为什么一定要加Bearer?这是规定。

    [HttpGet]
    public ActionResult<string> GetToken(string name, string pwd)
    {
        string jwtStr = string.Empty;
        bool suc = false;
        //这里就是用户登陆以后,通过数据库去调取数据,分配权限的操作
        //这里直接写死了
    
        if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(pwd))
        {
            return new JsonResult(new
            {
                Status = false,
                message = "用户名或密码不能为空"
            });
        }
    
        TokenModelJWT tokenModel = new TokenModelJWT();
        tokenModel.Uid = 1;
        tokenModel.Role = name;
    
        jwtStr = JwtHelper.IssueJWT(tokenModel);
        suc = true;
        return Ok(new
        {
            success = suc,
            token = jwtStr
        });
    }
    

    以上就是JWT的应用。

    Swagger中开启JWT服务

    我们要测试 JWT 授权认证,就必定要输入 Token令牌。Swagger 已经帮我们实现了这个录入 Token令牌的功能,需要在服务中开启:
    在ConfigureServices -> AddSwaggerGen 服务中,增加以下代码,注意是swagger服务内部:

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

    测试流程

    F5进入调试,进入Swagger界面,调用刚刚写的GetToken接口获取Token
    在这里插入图片描述
    将Token复制填到Authorize属性
    在这里插入图片描述
    最后访问我们之前加了[Authorize(Roles ="zzt")]特性的接口
    在这里插入图片描述
    可以看到是访问得到的,如果我们不带Token去访问的话会返回401的状态码,请求要求身份验证。
    完!

    参考文章:https://www.cnblogs.com/laozhang-is-phi/p/9511869.html#autoid-2-0-0

  • 相关阅读:
    Spring 增强类型
    Spring IOC及Bean的生命周期
    Spring
    Mybatis注解
    MyBatis关联查询
    LoadRunner(1)
    Selenium(6)
    Selenium(5)
    Selenium(4)
    Selenium(3)
  • 原文地址:https://www.cnblogs.com/zt102545/p/13940219.html
Copyright © 2020-2023  润新知