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!

posted @ 2020-07-09 17:12  Wahaha、  阅读(2004)  评论(3编辑  收藏  举报