asp.net Core Web api 适配jwt认证

一、创建项目遇到坑

1.创建项目vs未升级前创建项目模板未ASP.NET Core Web应用程序(创建后有一个可使用的swagger模板文件),升级到vs2019后模板不见了。解决方法:重新安装

安装步骤:

安装加载完毕后发现更名为Asp.net core web api (内容与之前一致,可正常使用swagger)

二、jwt添加认证

1.appSetting配置

创建一个AppSettings.cs类,存放读取配置信息的函数代码如下

2.引入包Microsoft.Extensions.Configuration、Microsoft.Extensions.Configuration.Json、Microsoft.Extensions.Configuration.Binder(配置时关联包)

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using System;
using System.Collections.Generic;
using System.Linq;

namespace WebApi.Core.Common
{
    public class AppSettings
    {
        static IConfiguration Configuration { get; set; }
        static string contentPath { get; set; }

        public AppSettings(string contentPath)
        {
            string Path = "appsettings.json";

            //如果你把配置文件 是 根据环境变量来分开了,可以这样写
            //Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json";

            Configuration = new ConfigurationBuilder()
               .SetBasePath(contentPath)
               .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话,可以直接读目录里的json文件,而不是 bin 文件夹下的,所以不用修改复制属性
               .Build();
        }

        public AppSettings(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// 封装要操作的字符
        /// </summary>
        /// <param name="sections">节点配置</param>
        /// <returns></returns>
        public static string app(params string[] sections)
        {
            try
            {

                if (sections.Any())
                {
                    return Configuration[string.Join(":", sections)];
                }
            }
            catch (Exception)
            {

            }

            return "";
        }

        /// <summary>
        /// 递归获取配置信息数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sections"></param>
        /// <returns></returns>
        public static List<T> app<T>(params string[] sections)
        {
            List<T> list = new List<T>();
            Configuration.Bind(string.Join(":", sections), list);
            return list;
        }
    }
}

3.注册刚添加的配置函数,位置webapi项目,Startup类,ConfigureService函数

services.AddSingletion(new AppSettings(Configuration));此处预留小坑(由于项目模板使用.netcore webapi 使得swagger在此处已经注册成功--已注册代码处)

 编辑appsettings.json,配置数据库链接地址

 4、重点来了!!注册使用Jwt,首先配置jwt需要的参数在appsettings.json中配置,注意SecretKey必须大于16个,小于或者等于会报错!

5、在Nuget中安装所使用的包IdentityModel、Microsoft.AspNetCore.Authentication.JwtBearer、Microsoft.AspNetCore.Authorization

6、新建model文件夹添加一个tokenmodel(存放jwt加密解析后的主要字段) 

using System;
using System.Collections.Generic;
using System.Text;

namespace testWebApi.Core.Model
{
    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModel
    {
        /// <summary>
        /// Id
        /// </summary>
        public string Uid { get; set; }
        /// <summary>
        /// 角色
        /// </summary>
        public string Role { get; set; }

    }
}

 7、在Api项目中新建一个文件夹 Authorization,新建一个JwtHelper  里面有生成token 和解析token 两个方法

using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.Common;
using WebApi.Core.Model;

namespace testWebApi.Core.Api.Authorization
{
    public class JwtHelper
    {
        /// <summary>
        /// 获取token信息
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string issueJwt(TokenModel tokenModel)
        {
            //获取Appsetting配置信息json文件配置
            string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
            string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });

            var claims = new List<Claim>
                {
                 /*
                 * 特别重要:
                   1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,              请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
                   2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */          //nbf 生效时间 、Jti 编号、iat 签发时间、aud 受众、exp 过期时间
                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()}") ,
                //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
                new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
                new Claim(JwtRegisteredClaimNames.Iss,iss),
                new Claim(JwtRegisteredClaimNames.Aud,aud),
               };

            // 可以将一个用户的多个角色全部赋予;
            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>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static TokenModel SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            object role;
            try
            {
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new TokenModel
            {
                Uid = jwtToken.Id.ToString(),
                Role = role != null ? role.ToString() : "",
            };
            return tm;
        }
    }
}

8、在UserController 新建一个login接口,获取token

/// <summary>
        /// 登录验证并且获取token
        /// </summary>
        /// <param name="loginModel"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult LoginValidate(LoginModel loginModel)
        {
            string jwtStr = string.Empty;
            bool suc = false;

            if (loginModel != null)
            {
                //加登录验证
                if (loginModel.UserName == "admin" && loginModel.PassWord == "123456")
                {
                    TokenModel tokenModel = new TokenModel { Uid = loginModel.UserName, Role = loginModel.Role };
                    jwtStr = JwtHelper.issueJwt(tokenModel);
                    suc = true;
                }
            }

            return Ok(new { 
                success=suc,
                token = jwtStr
            });
        }

9、F5启动后输入login中的用户名密码可发现已生成token

 10、上述将token已经拿到,后面就需要知道如何去使用

先安装包 Swashbuckle.AspNetCore.Filters

然后创建一个文件夹命名为SetupService ,主要是设置swagger的相关配置、注意:startup.cs文件中这一部分也存在,需要注释然在在startup中注册该部分配置!新建AddSwaggerSetUp方法中增加以下代码

public static void AddSwaggerSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            var ApiName = "Webapi.Core";

            services.AddSwaggerGen(c =>
            {
               // c.SwaggerDoc("V1", new OpenApiInfo
               // {
                    // {ApiName} 定义成全局变量,方便修改
                 //   Version = "V1",
                 //   Title = $"{ApiName} 接口文档——Netcore 3.0",
                 //   Description = $"{ApiName} HTTP API V1",

                });//此处为自定义,在startup.cs文件中也存在,如果直接使用这部分swagger会报错!所以被注释使用startup中提取的内容
              c.SwaggerDoc("v1", new OpenApiInfo { Title = "LZHY.GasAndCards.WebApi", Version = "v1" });


                c.OrderActionsBy(o => o.RelativePath);

                // 获取xml注释文件的目录
                var xmlPath = Path.Combine(AppContext.BaseDirectory, "WebApi.Core.Api.xml");
                c.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false,这个是controller的注释,记得修改

                // 获取xml注释文件的目录
                var xmlPathModel = Path.Combine(AppContext.BaseDirectory, "WebApi.Core.Model.xml");
                c.IncludeXmlComments(xmlPathModel, true);//默认的第二个参数是false,这个是controller的注释,记得修改

                //在 header中添加token,传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();

                #region Token绑定到configureServices

                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey
                });
                #endregion

            });

        }

此部分代码在startup中注册后,F5测试即可查看到相关授权按钮

 11、下面应进行授权token认证 在SetupService 文件夹下 新建一个AuthJwtSetup.cs 类 如下

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.Common;

namespace WebApi.Core.Api.SetUpService
{
    public static class AuthJwtSetup
    {
        public static void AddAuthorizationJwtSetUp(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            //读取配置文件
            var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });



            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,
                ValidAudience = Audience,//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(30), //token过期后 还可以继续多访问30秒
                RequireExpirationTime = true,
            };

            //2.1【认证】、core自带官方JWT认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服务
             .AddJwtBearer(o =>
             {
                 o.TokenValidationParameters = tokenValidationParameters;
                 o.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果过期,则把<是否过期>添加到,返回头信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });
        }
    }
}

startup.cs的ConfigureServices 方法添加 服务注入

注意如果位置添加反会造成接口401报错。

12、 接口授权策略验证,在UserController里面添加一个方法 

 13、这里如果swagger报错了, Conflicting method/path combination "POST api/DevTools" for actions 检查一下 action加没加,默认是不加的。

 14、接口验证

首先获取token,然后点击Authorize将token输入注意方法是Bearer {token}

填写一次后token则会保存,点击测试接口

 

上述图:完成jwt身份认证(在获取token时间Role一定需要填写正确,否则会报403)

14、 下面该解析Token 了,试一下,添加一个接口,步骤同上,先获取token,然后绑定token,最后调用一下解析接口,看结果我们已经解析成功了。

注意有空格,否则解析多出一个空格会报错

 15、解析完成

 

 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值