上接:.NetCore WebApi——Swagger简单配置
任何项目都有权限这一关键部分。比如我们有许多接口。有的接口允许任何人访问,另有一些接口需要认证身份之后才可以访问;以保证重要数据不会泄露。
关于JWT
维基百科上是这样定义的:
JWT(读作 [/d??t/]),即JSON Web Tokens,是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。它是一种用于双方之间传递安全信息的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的、自包含的方法,从而使通信双方实现以JSON对象的形式安全的传递信息。
认证的工作流程:
1. 客户端携带用户名、密码向授权服务申请 "令牌(token)"
2.授权服务器验证用户名、密码后根据它的身份生成一张专属的 "令牌" 并JWT的格式规范返回给客户端
3.客户端将获取到的令牌放入到http的请求头中,然后向资源服务器发起请求。服务器根据客户端发送过来的令牌来进行下一步处理(根据身份来响应客户端是否具有当前接口的权限)
如下图所示:

正文:
主要参考园友 在7楼 的这篇文章 https://www.cnblogs.com/RayWang/p/9536524.html
1. 启用Swagger的验证功能
在startup类中新添加红色部分代码。启动项目观察效果。
- // 注册Swagger服务
- services.AddSwaggerGen(c =>
- {
- // 添加文档信息
- c.SwaggerDoc("v1", new Info
- {
- Title = "CoreWebApi",
- Version = "v1",
- Description = "ASP.NET CORE WebApi",
- Contact = new Contact
- {
- Name = "Jee",
- Email = "xiaomaprincess@gmail.com",
- Url = "https://www.cnblogs.com/jixiaosa/"
- }
- });
- #region 读取xml信息
-
- // 使用反射获取xml文件。并构造出文件的路径
- var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
- var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
- // 启用xml注释. 该方法第二个参数启用控制器的注释,默认为false.
- c.IncludeXmlComments(xmlPath, true);
- #endregion
-
- #region 启用swagger验证功能
- //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称一致即可,CoreAPI。
- var security = new Dictionary<string, IEnumerable<string>> { { "CoreAPI", new string[] { } }, };
- c.AddSecurityRequirement(security);
- c.AddSecurityDefinition("CoreAPI", new ApiKeyScheme
- {
- Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
- Name = "Authorization",//jwt默认的参数名称
- In = "header",//jwt默认存放Authorization信息的位置(请求头中)
- Type = "apiKey"
- });
- #endregion
- });
没启动Swagger验证之前是这样的:

启用验证之后再看:多了个小按钮

点开之后是如下界面:文本框里要如输入从服务器获取的Token。格式为:Bearer + 空格+token。 Bearer可以看作是一个默认的规则。

2.生成token
.net core 内置了许多帮助类,巧妙的使用这些类组合,就可以生成我们想要的 token
新建一个tokenl类,编写一个方法来获取JWT字符串
- /// <summary>
- /// 生成JWT字符串
- /// </summary>
- public class Token
- {
- // 密钥,注意不能太短
- public static string secretKey { get; set; } = "xiaomaPrincess@gmail.com";
- /// <summary>
- /// 生成JWT字符串
- /// </summary>
- /// <param name="tokenModel"></param>
- /// <returns></returns>
- public static string GetJWT(TokenModel tokenModel)
- {
- //DateTime utc = DateTime.UtcNow;
- var claims = new List<Claim>
- {
- new Claim(JwtRegisteredClaimNames.Jti,tokenModel.ID.ToString()),
- // 令牌颁发时间
- new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
- new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
- // 过期时间 100秒
- new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(100)).ToUnixTimeSeconds()}"),
- new Claim(JwtRegisteredClaimNames.Iss,"API"), // 签发者
- new Claim(JwtRegisteredClaimNames.Aud,"User") // 接收者
- };
-
- // 密钥
- var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
- var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
- var tokenHandler = new JwtSecurityTokenHandler();
- JwtSecurityToken jwt = new JwtSecurityToken(
-
- claims: claims,// 声明的集合
- //expires: .AddSeconds(36), // token的有效时间
- signingCredentials: creds
- );
- var handler = new JwtSecurityTokenHandler();
- // 生成 jwt字符串
- var strJWT = handler.WriteToken(jwt);
- return strJWT;
- }
- }
基本信息类
- public class TokenModel
- {
- /// <summary>
- /// ID
- /// </summary>
- public int ID { get; set; }
- /// <summary>
- /// 名称
- /// </summary>
- public string Name { get; set; }
- /// <summary>
- /// 手机
- /// </summary>
- public string Phone { get; set; }
- /// <summary>
- /// 邮箱
- /// </summary>
- public string Email { get; set; }
- /// <summary>
- /// 身份
- /// </summary>
- public string Sub { get; set; }
- }
添加一个方法来获取token
- /// <summary>
- /// 获取令牌
- /// </summary>
- /// <param name="ID">ID</param>
- /// <param name="name">账号</param>
- /// <returns></returns>
- [HttpPost]
- public string GetJwt(int ID,string name)
- {
- TokenModel tokenModel = new TokenModel
- {
- ID = ID,
- Name=name
- };
- return Token.GetJWT(tokenModel);
- }
在Startup类中配置身份认证服务
(1)在ConfigureServices方法中注册服务
- #region 添加验证服务
-
- // 添加验证服务
- services.AddAuthentication(x =>
- {
- x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
- x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
- }).AddJwtBearer(o =>
- {
- o.TokenValidationParameters = new TokenValidationParameters
- {
- // 是否开启签名认证
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Token.secretKey)),
- // 发行人验证,这里要和token类中Claim类型的发行人保持一致
- ValidateIssuer = true,
- ValidIssuer = "API",//发行人
- // 接收人验证
- ValidateAudience = true,
- ValidAudience = "User",//订阅人
- ValidateLifetime = true,
- ClockSkew = TimeSpan.Zero,
- };
- });
- #endregion
(2)在Configure方法中启用验证中间件
- // 启用Swagger中间件
- app.UseSwagger();
- // 配置SwaggerUI
- app.UseSwaggerUI(c =>
- {
- c.SwaggerEndpoint("/swagger/v1/swagger.json", "CoreAPI");
- c.RoutePrefix = string.Empty;
- });
- // 启用认证中间件
- app.UseAuthentication();
- app.UseMvc();
3. 添加一个测试测控制器来检测是否成功
注意要添加 [Authorize]标签
- /// <summary>
- /// 需要身份认证的控制器
- /// </summary>
- [Route("api/[controller]/[action]")]
- [Produces("application/json")]
- [ApiController]
- [Authorize]// 添加授权特性
- public class TestController : ControllerBase
- {
- /// <summary>
- /// 认证通过之后可访问
- /// </summary>
- /// <returns></returns>
- [HttpPost]
- public ActionResult<TokenModel> Get(TokenModel tokenModel)
- {
- return new TokenModel{ ID=1 };
- }
- }
启动项目
测试一: 在没有获取token时访问此方法

返回401 身份验证未通过
测试二:先访问GetJWT接口获取token,在访问Test接口


最后将获取的token输入到Swagger的文本框中:Bearer +空格+Token

再次访问Test接口:成功返回数据

至此,一个简单身份认证加授权就完成了。
推荐一篇大神的文章 :讲述Claim的