.net6 webapi 项目搭建(一、swagger配置和jwt认证)

1,077 阅读3分钟

一、swagger配置文档注释

使用visual studio 创建webapi项目会生成一个获取天气的接口swagger文档示例,在项目解决方案管理器中右键选中创建的项目,选中编辑项目文件,在PropertyGroup标签底下加入这句代码:

<GenerateDocumentationFile>True</GenerateDocumentationFile>

然后在program.cs里面找到AddSwaggerGen方法,加入以下片段:

builder.Services.AddSwaggerGen(options => {
    //swagger文档注释
    var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), true);
});

报错的尝试快捷键alt + enter显示可能修补的程序。

最后在控制器中使用文档注释即可在swagger文档上显示。

二、权限校验

1、swagger添加授权框

在program.cs里面加上如下代码

#region swagger jwt认证授权框
builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {
        Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        BearerFormat = "JWT",
        Scheme = "Bearer"
    });
    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] { }
        }
    });
});
#endregion

2、jwt配置

安装以下nuget包

Snipaste_2022-06-16_23-23-02.png 如果下载不成功可以尝试换一下程序包源:

Snipaste_2022-06-16_23-25-53.png

新建一个JwtHelper类

     public class JwtHelper
    {
        /// <summary>
        /// 创建Jwt字符串
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static string CreateJwt(TokenModelJwt model)
        {
            var claims = new List<Claim>
                {
                 /*
                 * 特别重要:
                   1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
                   2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */
                new Claim("UserId",model.UserId.ToString()),
                new Claim("UserName",model.UserName),
                //new Claim(ClaimTypes.Role,tokenModel.Role),//为了解决一个用户多个角色(比如:Admin,System),用下边的方法
               };

            // 可以将一个用户的多个角色全部赋予;
            // 作者:DX 提供技术支持;
            if (!string.IsNullOrWhiteSpace(model.Role))
            {
                claims.AddRange(model.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
                claims.Add(new Claim("Role", model.Role));
            }

            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(model.Secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: model.Issuer,
                audience: model.Audience,
                expires: DateTime.Now.AddSeconds(model.Expires),
                signingCredentials: creds,
                claims: claims
            );

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

            return token;
        }

        /// <summary>
        /// 解析
        /// </summary>
        /// <param name="jwtStr">如果为null将报错</param>
        /// <returns></returns>
         public static TokenModelJwt SerializeJwt(string jwtStr)
        {
            //截取字符串 把bearer 去掉不然解析失败
            string str = "";
            if (jwtStr.Contains("Bearer "))
            {
                str = jwtStr.Substring("Bearer ".Length, jwtStr.Length - "Bearer ".Length);
            }
            else
            {
                str = jwtStr;
            }

            //尝试解析token
            try
            {
                var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(str);
                var tokenJwt = JsonConvert.DeserializeObject<TokenModelJwt>(jwtToken.Payload.SerializeToJson());
                return tokenJwt;
            }
            catch (Exception)
            {
                return null;
            }

        }

    }
    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModelJwt
    {

        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Issuer { get; set; }
        public string Audience { get; set; }
        public string Secret { get; set; }
        public int Expires { get; set; }
        public string Role { get; set; }
    }

在appsetting.json里面配置加密字符串

"Jwt": {
    "Secret": "skumallliulingshsoxijs", //不要太短,有可能会报异常
    "Issuer": "LL",
    "Audience": "LL"
}

program.cs里面加上以下代码:

#region Jwt
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        var tokenModel = builder.Configuration.GetSection("Jwt").Get<TokenModelJwt>();
        var secretByte = Encoding.UTF8.GetBytes(tokenModel.Secret);
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidIssuer = tokenModel.Issuer,

            ValidateAudience = true,
            ValidAudience = tokenModel.Audience,

            ValidateLifetime = true,

            IssuerSigningKey = new SymmetricSecurityKey(secretByte)
        };
        options.Events = new JwtBearerEvents
        {
            OnChallenge = context =>
            {
                //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦,必须
                //context.HandleResponse();

                //自定义自己想要返回的数据结果,我这里要返回的是Json对象,通过引用Newtonsoft.Json库进行转换

                //自定义返回的数据类型
                //context.Response.ContentType = "text/plain";
                ////自定义返回状态码,默认为401 我这里改成 200
                ////context.Response.StatusCode = StatusCodes.Status200OK;
                //context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                ////输出Json数据结果
                //context.Response.WriteAsync("expired");
                return Task.FromResult(0);
            },
            //403
            OnForbidden = context =>
            {
                //context.Response.ContentType = "text/plain";
                ////自定义返回状态码,默认为401 我这里改成 200
                ////context.Response.StatusCode = StatusCodes.Status200OK;
                //context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                ////输出Json数据结果
                //context.Response.WriteAsync("expired");
                return Task.FromResult(0);
            }

        };
    });
#endregion

在控制器接口上添加认证 Authorize

1asd.png

运行项目try一下,应该会返回401未授权状态码。

3、模拟登录返回token

在控制器中加入以下方法测试:

        /// <summary>
        /// 测试是否能返回token 
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        [HttpPost(Name = "Login")]
        public string Login(string account , string password)
        {
            //仅为模拟用户输入登录的情况
            if(account == "123456" && password == "123456")
            {
                //这一段为获取appsettings.json定义的数据 , 可以忽视,后面用依赖注入的方法会更加方便
                IConfiguration configuration = new
                 ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).Add(new JsonConfigurationSource
                {
                    Path = "appsettings.json",
                    ReloadOnChange = true
                }).Build();;
                TokenModelJwt tokenModel = configuration.GetSection("Jwt").Get<TokenModelJwt>();

                tokenModel.UserId = 1;
                tokenModel.Role = "Admin";
                tokenModel.UserName = "用户名";
                return JwtHelper.CreateJwt(tokenModel);
            }
            return "账号密码错误";
        }

运行调用接口获取到token

token.png

复制得到的token,在swagger中认证然后测试获取数据

jwt.png

tian.png

成功获取。