[WebApi]ASP.Net Core 中使用JWT认证(3.1版本,5.0也可以使用)
Posted 厦门德仔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[WebApi]ASP.Net Core 中使用JWT认证(3.1版本,5.0也可以使用)相关的知识,希望对你有一定的参考价值。
ASP.Net Core 中使用JWT认证
JWT简单介绍
关于JWT网上有很多介绍,这里就不介绍了,本文主要以实现为主。
JWT由3部分构成:
HEADER 、PAYLOAD 、SIGNATURE
HEADER :包含token的元数据,主要是加密算法,和签名的类型,如下面的信息,说明了加密的对象类型是JWT,加密算法是HMAC SHA-256
"alg":"HS256","typ":"JWT"
PAYLOAD :主要包含一些声明信息(claim),这些声明是key-value对的数据结构。通常如用户名,角色等信息,过期日期等,因为是未加密的,所以不建议存放敏感信息。
SIGNATURE:jwt要符合jws(Json Web Signature)的标准生成一个最终的签名。把编码后的Header和Payload信息加在一起,然后使用一个强加密算法进行加密。HS256(BASE64(Header).Base64(Payload),secret)
开始编码
首先我们先创建一个ASP.NET Core Web API项目 版本随意。
创建好项目后我们先创建几个文件夹,分别是Model、IdentityService。
然后我们在Model文件夹中创建一个TokenModel的类用来存储签发或者验证时的信息。如下:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZettlercnMIS.Api.Models
public class tokenModel
/// <summary>
/// 密钥
/// </summary>
public string Secret get; set;
/// <summary>
/// 发布者
/// </summary>
public string Issuer get; set;
/// <summary>
/// 接收者
/// </summary>
public string Audience get; set;
/// <summary>
/// 过期时间
/// </summary>
public int AccessExpiration get; set;
/// <summary>
/// 刷新时间
/// </summary>
public int RefreshExpiration get; set;
然后在 appsettings.Development.json 增加jwt使用到的配置信息(如果是生成环境在appsettings.json添加即可)
"JWTTokenconfig":
"Secret": "fsdjfljoiuweihjfskghrfygierwuer9uwekhdkcnh940233+f+s",
"Issuer": "dezai.cn", //wkea.cn
"Audience": "user",//user
"AccessExpiration": 30,
"RefreshExpiration": 60
,
然后在startup.cs类中的ConfigureServices方法中读取配置
public void ConfigureServices(IServiceCollection services)
services.AddControllers();
services.AddSwaggerGen(c =>
c.SwaggerDoc("v1", new OpenApiInfo Title = "testjwt", Version = "v1" );
);
services.Configure<tokenModel>(Configuration.GetSection("JWTTokenconfig"));
var token = Configuration.GetSection("JWTTokenconfig").Get<tokenModel>();
到目前为止,我们完成了一些基础工作,下面再webapi中注入jwt的验证服务,并在中间件管道中启用authentication中间件。startup类中要引用jwt验证服务的命名空间。注:这两个包要自己NuGet下载下来。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
然后在ConfigureServices方法中添加如下配置
services.AddAuthentication(option =>
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(option =>
option.RequireHttpsMetadata = false;
option.SaveToken = true;
option.TokenValidationParameters = new TokenValidationParameters
ValidateIssuer = false,//是否验证Issuer
ValidateAudience = false,//是否验证Audience
ValidateIssuerSigningKey = true,//是否验证SigningKey
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Secret)),//拿到SigningKey
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ClockSkew = TimeSpan.FromMinutes(0)//设置缓冲时间,token的总有有效时间等于这个时间加上jwt的过期时间,如果不配置默认是5分钟
;
);
再在Configure方法中启用验证
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "testjwt v1"));
app.UseHttpsRedirection();
app.UseRouting();
//开启下面两个配置
app.UseAuthentication();//认证
app.UseAuthorization();//授权
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
);
注意,这里必须要把认证和授权都开启,如果只开一个在后面验证时一直都会报一个401错误,而且二者顺序不能倒置。
上面完成了JWT验证的功能。接下来就是实现jwttoken的签发流程了。一般我们的流程是用户输入账号密码我们校验是否正确,再确定是否签发token.
下面我们创建一个用户类Users用来模拟正常的模拟登录时存储用户信息,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZettlercnMIS.Api.Models
public class User
public string UserName get; set;
public string Password get; set;
然后创建一个控制器来让用户请求token
namespace ZettlercnMIS.Api.Controllers
[Route("api/[controller]/[action]")]
public class HomeController : Controller
[HttpGet]
public string GetToken(User user)
return "";
目前上面的控制器只实现了基本的逻辑,下面我们要创建签发token的服务,去完成具体的业务。第一步我们先在IdentityServer文件夹下创建对应的服务接口,命名为IAuthenticateService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using testjwt.Models;
namespace ZettlercnMIS.Api.Controllers
public interface IAuthenticateService
bool IsAuthenticated(User request, out string token);
然后实现接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using testjwt.Models;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
namespace ZettlercnMIS.Api.Controllers
public class AuthenticateService : IAuthenticateService
public bool IsAuthenticated(User request, out string token)
throw new NotImplementedException();
在Startup的ConfigureServices方法中注册服务
services.AddScoped<IAuthenticateService, AuthenticateService>();
1
然后在HomeController中注入IAuthenticateService服务,具体如下
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ZettlercnMIS.Api.IdentityServer;
using ZettlercnMIS.Api.Models;
using ZettlercnMIS.Utility;
namespace ZettlercnMIS.Api.Controllers
[Route("api/[controller]/[action]")]
public class HomeController : Controller
private readonly IAuthenticateService _authenservice;
public HomeController(IAuthenticateService service)
_authenservice = service;
/// <summary>
/// 通过身份验证获取token令牌
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public LoginResult GetToken([FromBody] User user)
LoginResult rs = new LoginResult();
///正常来说这里应该是链接数据库查询用户名密码是否正确,但是这里我们直接模拟一下测试就可以了
if (user.UserName != "abc" || user.Password != "123")
rs.Message = "fail";
rs.Success = false;
//签发token
string token;
if (_authenservice.IsAuthenticated(user, out token))
rs.Message = "已获取token";
rs.Token = token;
rs.Success = true;
return rs;
/// <summary>
/// 测试一个带身份验证的API接口
/// </summary>
/// <returns></returns>
[Authorize]
[HttpGet]
public string GetAPI()
return "";
将User注入到容器中
services.AddScoped<User>();
接下来我们完善一下继承了IAuthenticateService接口的AuthenticateService类,首先先注入tokenmodel,然后实现一下生成token的逻辑
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using ZettlercnMIS.Api.Models;
namespace ZettlercnMIS.Api.IdentityServer
public class AuthenticateService : IAuthenticateService
public readonly tokenModel _jwtModel;
public AuthenticateService(IOptions<tokenModel> jwtModel)
_jwtModel = jwtModel.Value;
public bool IsAuthenticated(User user, out string token)
token = string.Empty;
var claims = new[]
new Claim(ClaimTypes.Name,user.UserName),
new Claim(ClaimTypes.Role, "admin, Manage")
;
//密钥
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtModel.Secret));
//凭证
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
//生成Token
var jwtToken = new JwtSecurityToken(
_jwtModel.Issuer,
_jwtModel.Audience,
claims,
expires: DateTime.Now.AddMinutes(_jwtModel.AccessExpiration),
signingCredentials:
credentials);
token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
return true;
特别注意下tokenmodel的注入是以IOptions的接口类型注入的,在Startpup中我们是通过配置项的方式注册tokenmodel类型的。
以上就已经实现jwttoken验证的基本方法了,HOME控制器来测试一下
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ZettlercnMIS.Api.IdentityServer;
using ZettlercnMIS.Api.Models;
using ZettlercnMIS.Utility;
namespace ZettlercnMIS.Api.Controllers
[Route("api/[controller]/[action]")]
public class HomeController : Controller
private readonly IAuthenticateService _authenservice;
public HomeController(IAuthenticateService service)
_authenservice = service;
/// <summary>
/// 通过身份验证获取token令牌
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
public LoginResult GetToken([FromBody] User user)
LoginResult rs = new LoginResult();
///正常来说这里应该是链接数据库查询用户名密码是否正确,但是这里我们直接模拟一下测试就可以了
if (user.UserName != "abc" || user.Password != "123")
rs.Message = "fail";
rs.Success = false;
//签发token
string token;
if (_authenservice.IsAuthenticated(user, out token))
rs.Message = "已获取token";
rs.Token = token;
rs.Success = true;
return rs;
/// <summary>
/// 测试一个带身份验证的API接口
/// </summary>
/// <returns></returns>
[Authorize]
[HttpGet]
public string GetAPI()
return "恭喜你又学会一个新技能!";
这里加上了[Authorize]特性就说明要校验token
运行项目
我们先不获取token然后直接去请求test
发生了401错误,就是token验证失败
接下来我们测试获取token,我们写死的账号密码,张三、123
获取到了token,接下来我们用接口测试工具带上token来测试一下test(别问为什么要用接口测试工具,但凡swagger要是支持在请求头里面写数据我也不会专门下个测试工具。),这里我用的是apipost怎么使用这里就不阐述了。
记得这里选Bearer auth认证,因为我们在配置的时候使用的时这个。然后将生成的token复制过去然后点击发送,这个时候就请求成功了。
为方面演示:利用Jquery 前端ajax提交请求
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<meta charset="utf-8" />
@*<script src="~/lib/jquery/dist/jquery.min.js"></script>*@
<script src="~/lib/jquery-3.3.1/jquery-3.1.1.js"></script>
<script src="~/lib/jquery-3.3.1/jquery-3.1.1.min.js"></script>
</head>
<body>
<fieldset>
<legend>身份验证</legend>
<form id="login_form">
<label for="UserName">用户名:</label><input type="text" name="userName" id="userName" value="admin" />
获取 ASP .Net Core WebAPI 中的所有身份角色
ASP.NET Core 2.2 WebAPI 405 方法不允许
ASP.NET Core 5.0 WebAPI 中的多种身份验证方案
在 ASP.NET Core WebAPI 中获取 OData 计数