• ASP.NET Core WebApi使用JWT认证


    什么是JWT:https://www.cnblogs.com/yan7/p/7857833.html

    在前后端分离开发中会需要进行用户验证,本篇博客介绍如何在ASP.NET Core WebApi中使用JWT进行用户认证。

    本篇博客延续上一篇博客 https://www.cnblogs.com/gygg/p/12849641.html 配置swagger验证功能

    开发工具:Visual Studio2019

    目标框架:.NET Core 3.1

    一、启用swagger验证功能

    1.1、AddSwaggerGen()方法中启用swagger验证功能,添加全局安全条件,自定义Heard Token

    services.AddSwaggerGen(c =>
    {
        //启用swagger验证功能
        c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
        {
            Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
            Name = "Authorization",//jwt默认的参数名称
            In = ParameterLocation.Header,//jwt默认存放authorization信息的位置(请求头中)
            Type = SecuritySchemeType.ApiKey,
            BearerFormat = "JWT",
            Scheme = "Bearer"
        });
        //添加全局安全条件
        c.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme{
                    Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"}
                },new string[] { }
            }
        });
        //显示自定义的Heard Token
        c.OperationFilter<AuthTokenHeaderParameter>();
    });

    1.2、添加 AuthTokenHeaderParameter 类,显示自定义的Heard Token

    public class AuthTokenHeaderParameter : IOperationFilter
        {
            public void Apply(OpenApiOperation operation, OperationFilterContext context)
            {
                operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>();
                var isAuthor = operation != null && context != null;
                if (isAuthor)
                {
                    //in query header 
                    operation.Parameters.Add(new OpenApiParameter()
                    {
                        Name = "Authorization",
                        Description = "身份验证",
                        Required = false,
                        In = ParameterLocation.Header
                    });
                }
                if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) &&
                   !context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }
            }
        }

    启动项目,效果图如下

     

    2、注册JWT

    2.1、添加 JWTTokenOptions 类

    public class JWTTokenOptions
    {
        /// <summary>
        /// 订阅者
        /// </summary>
        public string Audience { get; set; }
        /// <summary>
        /// 发起人
        /// </summary>
        public string Issuer { get; set; }
        /// <summary>
        /// 过期时间 单位秒
        /// </summary>
        public long Expire { get; set; }
        /// <summary>
        /// 秘钥
        /// </summary>
        public string Secret { get; set; }
    }
    

    2.2、在 appsettings.json 中配置JWTToken

    "JWTToken": {
      "Expire": 3600, //token过期时间 单位s
      "Audience": "www.baidu.com", //订阅者
      "Issuer": "baidu", //发起人
      "Secret": "************************" //秘钥
    }
    

    2.3、在 startup 类的 ConfigureServices 方法中注册 jwt

    #region 注册jwt
    JWTTokenOptions JWTTokenOptions = new JWTTokenOptions();
    
    //获取appsettings的内容
    services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTToken"));
    //将给定的对象实例绑定到指定的配置节
    Configuration.Bind("JWTToken", JWTTokenOptions);
    
    //注册到Ioc容器
    services.AddSingleton(JWTTokenOptions);
    
    //添加验证服务
    services.AddAuthentication(option =>
    {
        //默认身份验证模式
        option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        //默认方案
        option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    
    }).AddJwtBearer(option =>
    {
        //设置元数据地址或权限是否需要HTTP
        option.RequireHttpsMetadata = false;
        option.SaveToken = true;
        //令牌验证参数
        option.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            //获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.
            GetBytes(JWTTokenOptions.Secret)),
            //获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。 
            ValidIssuer = JWTTokenOptions.Issuer,
            //获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。
            ValidAudience = JWTTokenOptions.Audience,
            //是否验证发起人
            ValidateIssuer = false,
            //是否验证订阅者
            ValidateAudience = false,
            ////允许的服务器时间偏移量
            ClockSkew = TimeSpan.Zero,
            ////是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
            ValidateLifetime = true
        };
        //如果jwt过期,在返回的header中加入Token-Expired字段为true,前端在获取返回header时判断
        option.Events = new JwtBearerEvents()
        {
            OnAuthenticationFailed = context =>
            {
                if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                {
                    context.Response.Headers.Add("Token-Expired", "true");
                }
                return Task.CompletedTask;
            }
        };
    });
    #endregion

    2.4、在 startup 类的 Configure 方法中添加认证

    app.UseAuthentication();  //添加认证
    app.UseAuthorization();   //添加授权(.netCore 3.x中使用)

    3、生成JWT

    3.1、添加 TokenResult 类

    public class TokenResult
    {
        /// <summary>
        /// token字符串
        /// </summary>
        public string Access_token { get; set; }
    
        /// <summary>
        /// 过期时间
        /// </summary>
        public long Expires_in { get; set; }
    }
    

    3.2、添加 JwtTokenHelper 类

    public class JwtTokenHelper
    {
        public JwtTokenHelper()
        {
        }
    
        public TokenResult AuthorizeToken(int memberId, JWTTokenOptions _tokenOptions)
        {
            //基于声明的认证
            var claims = new[]
            {
                new Claim(ClaimTypes.Name,memberId.ToString()),
                new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())//jwt的唯一标识
            };
            //秘钥 转化成UTF8编码的字节数组
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenOptions.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//资格证书 秘钥加密
            var jwtToken = new JwtSecurityToken(_tokenOptions.Issuer, _tokenOptions.Audience, claims,//发起人 订阅者
                expires: DateTime.Now.AddSeconds(_tokenOptions.Expire),//过期时间
                signingCredentials: credentials);//秘钥
            var securityToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);//序列化jwt格式
    
            //生成令牌字符串
            return new TokenResult()
            {
                Access_token = "Bearer " + securityToken,
                Expires_in = _tokenOptions.Expire
            };
        }
    }
    

    3.3、添加生成 JWT 方法

    [ApiController]
    [Route("api/[controller]/[action]")]
    public class HomeController : Controller
    {
        private readonly JWTTokenOptions _tokenOptions;
        public HomeController(JWTTokenOptions tokenOptions)
        {
            _tokenOptions = tokenOptions;
        }
        /// <summary>
        /// 生成jwt
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public TokenResult GenerateJwt()
        {
            var token = new JwtTokenHelper().AuthorizeToken(123456, _tokenOptions);
            return token;
        }
    }
    

    执行 GenerateJwt 方法,生成 jwt

    在需要认证的 Controller 中添加 [Authorize] 特性

    若未进行jwt认证,则报错401

    若进行了jwt 认证,则正常返回接口

    End!

  • 相关阅读:
    python学习之路(3)
    扫描工具-Nikto
    python学习之路(2)(渗透信息收集)
    openvas 安装
    python 学习之路(1)
    BZOJ4004:[JLOI2015]装备购买——题解
    HDU3949:XOR——题解
    洛谷3812:【模板】线性基——题解
    BZOJ4566:[HAOI2016]找相同字符——题解
    BZOJ3238:[AHOI2013]差异——题解
  • 原文地址:https://www.cnblogs.com/gygg/p/13274708.html
Copyright © 2020-2023  润新知