给.Net 5 Api增加JwtBearer认证

给.Net 5 Api增加JwtBearer认证

ZKEASOFT December 26, 2020


JSON WEB TOKEN

JWT是Json Web Token的缩写。JWT, 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

安装包引用

这里我们需要安装两个nuget包,所以在开始之前,请先通过nuget管理工具安装:

Microsoft.AspNetCore.Authentication.JwtBearer这个用于做JWT Token的生成和认证。Swashbuckle.AspNetCore这个方便在开发环境调用调式API。

Add Authentication

接下来我们来添加JwtBearer认证,打开Startup.cs文件,然后在ConfigureServices(IServiceCollection services)方法中添加以下代码:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidIssuer = "Security:Tokens:Issuer",
            ValidateAudience = true,
            ValidAudience = "Security:Tokens:Audience",
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Security:Tokens:Key"))
        };
    });

这样系统就支持JWT认证了,接下来就可以在要使用认证的API中添加JWT认证了。在API上增加Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)即可:

[HttpGet("Get"), Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IEnumerable<WeatherForecast> Get()
{
    var rng = new Random();
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    })
    .ToArray();
}

生成JWT Token

现在GetAPI已经是需要认证才能调用了,所以我们需要生成一个JWT Token,并在调用API的时候带上这个Token,这样可以调用API了。

我们写一个BuildToken的私有方法,该方法用于将用户的ID生成为Token:

private string BuildToken(string userId)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes("Security:Tokens:Key");
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Issuer = "Security:Tokens:Issuer",
        Audience = "Security:Tokens:Audience",
        Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, userId) }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

再写一个API来返回这个Token。在实际项目中,可以通过用户名和密码来确认用户,确认成功后再返回对应的Token。这里为了方便,就直接返回admin用户的Token:

[HttpGet("GetToken")]
public IActionResult GetToken()
{
    return Ok(new { Token = BuildToken("admin") });
}

使用Swagger调用API

API的JWT认证已经配置完成了,接下来我们来配置swagger,swagger可以很方便的调用API。

同样打开Startup.cs文件,并在ConfigureServices(IServiceCollection services)方法中添加以下代码:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPI", Version = "v1" });
    var securityScheme = new OpenApiSecurityScheme
    {
        Name = "JWT Authentication",
        Description = "Enter JWT Bearer token **_only_**",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer", 
        BearerFormat = "JWT",
        Reference = new OpenApiReference
        {
            Id = JwtBearerDefaults.AuthenticationScheme,
            Type = ReferenceType.SecurityScheme
        }
    };
    c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        { securityScheme, new string[] { } }
    });
});

然后在Configure(IApplicationBuilder app, IWebHostEnvironment env)方法中添加以下代码:

app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPI v1"));

这样所有配置就完成了。运行项目进行测试。

测试API

我们先直接测试一下GetAPI,点击“Try it out”:

然后点击"Execute":

API返回了401,说明API现在不能调用成功,需要认证:

获取Token

我们通过调用GetTokenAPI来获取Token:

然后复制Token内容,注意不要复制整个结果,只要复制token的值就可以了:

然后点击“Authorize”,粘贴刚刚复制的Token后再点击Authorize就可以了,

blobid6.png

我们再调用一次GetAPI试试,现在已经可以调用成功了:

完整源代码:https://github.com/SeriaWei/JwtBearerWebAPI


微信公众号