在.NET Core中使用Jwt对API进行认证
在.NET Core中想给API进行安全认证,最简单的无非就是Jwt,悠然记得一年前写的Jwt Demo,现在拿回来改成.NET Core的,但是在编码上的改变并不大,因为Jwt已经足够强大了。在项目中分为 DotNetCore_Jwt_Server 以及 DotNetCore_Jwt_Client ,从名字就可以看出来是啥意思,博客园高手云集,我就不多诉说,这篇博客就当是一篇记录。
当然本案例是Server&Client双项目,如果你要合成自己发证的形式,那你就自己改下代码玩。
在Server层都会有分发Token的服务,在其中做了用户密码判断,随后根据 Claim 生成 jwtToken 的操作。
其生成Token的服务代码:
namespace DotNetCore_Jwt_Server.Services
{
public interface ITokenService
{
string GetToken(User user);
}
public class TokenService : ITokenService
{
private readonly JwtSetting _jwtSetting;
public TokenService(IOptions<JwtSetting> option)
{
_jwtSetting = option.Value;
}
public string GetToken(User user)
{
//创建用户身份标识,可按需要添加更多信息
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("id", user.Id.ToString(), ClaimValueTypes.Integer32),
new Claim("name", user.Name),
new Claim("admin", user.IsAdmin.ToString(),ClaimValueTypes.Boolean)
}; //创建令牌
var token = new JwtSecurityToken(
issuer: _jwtSetting.Issuer,
audience: _jwtSetting.Audience,
signingCredentials: _jwtSetting.Credentials,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(_jwtSetting.ExpireSeconds)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return jwtToken;
}
}
}
在获取Token中我们依赖注入服务到控制器中,随后依赖它进行认证并且分发Token,
public class ValuesController : ControllerBase
{
private readonly IUserService _userService;
private readonly ITokenService _tokenService; public ValuesController(IUserService userService,
ITokenService tokenService)
{
_userService = userService;
_tokenService = tokenService;
}
[HttpGet]
public async Task<string> Get()
{
await Task.CompletedTask;
return "Welcome the Json Web Token Solucation!";
}
[HttpGet("getToken")]
public async Task<string> GetTokenAsync(string name, string password)
{
var user = await _userService.LoginAsync(name, password);
if (user == null)
return "Login Failed"; var token = _tokenService.GetToken(user);
var response = new
{
Status = true,
Token = token,
Type = "Bearer"
};
return JsonConvert.SerializeObject(response);
}
}
随后,我们又在项目配置文件中填写了几个字段,相关备注已注释,但值得说明的是有位朋友问我,服务器端生成的Token不需要保存吗,比如Redis或者是Session,其实Jwt Token是无状态的,他们之间的对比第一个是你的token解密出来的信息正确与否,第二部则是看看你 SecurityKey 是否正确,就这样他们的认证才会得出结果。
"JwtSetting": {
"SecurityKey": "d0ecd23c-dfdb-4005-a2ea-0fea210c858a", // 密钥
"Issuer": "jwtIssuertest", // 颁发者
"Audience": "jwtAudiencetest", // 接收者
"ExpireSeconds": // 过期时间
}
随后我们需要DI两个接口以及初始化设置相关字段。
public void ConfigureServices(IServiceCollection services)
{
services.Configure<JwtSetting>(Configuration.GetSection("JwtSetting"));
services.AddScoped<IUserService, UserService>();
services.AddScoped<ITokenService, TokenService>();
services.AddControllers();
}
在Client中,我一般会创建一个中间件用于接受认证结果,AspNetCore Jwt 源码中给我们提供了中间件,我们在进一步扩展,其源码定义如下:
/// <summary>
/// Extension methods to expose Authentication on HttpContext.
/// </summary>
public static class AuthenticationHttpContextExtensions
{/// <summary>
/// Extension method for authenticate.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <param name="scheme">The name of the authentication scheme.</param>
/// <returns>The <see cref="AuthenticateResult"/>.</returns>
public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) =>
context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);
}
其该扩展会返回一个 AuthenticateResult 类型的结果,其定义部分是这样的,我们就可以将计就计,给他来个连环套。

连环套直接接受 httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme) 返回回来的值,随后进行判断返回相应的Http响应码。
public class AuthMiddleware
{
private readonly RequestDelegate _next; public AuthMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var result = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (!result.Succeeded)
{
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await httpContext.Response.WriteAsync("Authorize error");
}
else
{
httpContext.User = result.Principal;
await _next.Invoke(httpContext);
}
}
}
当然你也得在Client中添加认证的一些设置,它和Server端的 IssuerSigningKey 一定要对应,否则认证失败。
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddScoped<IIdentityService, IdentityService>();
var jwtSetting = new JwtSetting();
Configuration.Bind("JwtSetting", jwtSetting); services.AddCors(options =>
{
options.AddPolicy("any", builder =>
{
builder.AllowAnyOrigin() //允许任何来源的主机访问
.AllowAnyMethod()
.AllowAnyHeader(); });
}); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = jwtSetting.Issuer,
ValidAudience = jwtSetting.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecurityKey)),
默认 300s
ClockSkew = TimeSpan.Zero
};
});
services.AddControllers();
}
随后,你就可以编写带需认证才可以访问的API了,如果认证失败则会返回401的错误响应。
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IIdentityService _identityService;
public ValuesController(IIdentityService identityService)
{
_identityService = identityService;
}
[HttpGet]
[Authorize]
public async Task<string> Get()
{
await Task.CompletedTask;
return $"{_identityService.GetUserId()}:{_identityService.GetUserName()}";
}
值得一提的是,我们可以根据 IHttpContextAccessor 以来注入到我们的Service或者Api中,它是一个当前请求的认证信息上下文,这将有利于你获取用户信息去做该做的事情。
public class IdentityService : IIdentityService
{
private readonly IHttpContextAccessor _context;
public IdentityService(IHttpContextAccessor context)
{
_context = context;
}
public int GetUserId()
{
var nameId = _context.HttpContext.User.FindFirst("id"); return nameId != null ? Convert.ToInt32(nameId.Value) : ;
}
public string GetUserName()
{
return _context.HttpContext.User.FindFirst("name")?.Value;
}
}
在源码中该类的定义如下,实际上我们可以看到只不过是判断了当前的http上下文吧,所以我们得出,如果认证失败,上下本信息也是空的。
public class HttpContextAccessor : IHttpContextAccessor
{
private static AsyncLocal<HttpContextHolder> _httpContextCurrent = new AsyncLocal<HttpContextHolder>(); public HttpContext HttpContext
{
get
{
return _httpContextCurrent.Value?.Context;
}
set
{
var holder = _httpContextCurrent.Value;
if (holder != null)
{
// Clear current HttpContext trapped in the AsyncLocals, as its done.
holder.Context = null;
} if (value != null)
{
// Use an object indirection to hold the HttpContext in the AsyncLocal,
// so it can be cleared in all ExecutionContexts when its cleared.
_httpContextCurrent.Value = new HttpContextHolder { Context = value };
}
}
} private class HttpContextHolder
{
public HttpContext Context;
}
}
如果要通过js来测试代码,您可以添加请求头来进行认证,beforeSend是在请求之前的事件。
beforeSend : function(request) {
request.setRequestHeader("Authorization", sessionStorage.getItem("Authorization"));
}
好了,今天就说到这,代码地址在https://github.com/zaranetCore/DotNetCore_Jwt 中。

在.NET Core中使用Jwt对API进行认证的更多相关文章
- 如何简单的在 ASP.NET Core 中集成 JWT 认证?
前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...
- .net core中使用jwt进行认证
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息.由于此信息是经过数字签名的,因此可以被验证和信任 ...
- 如何在ASP.NET Core中实现一个基础的身份认证
注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...
- [转]如何在ASP.NET Core中实现一个基础的身份认证
本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...
- 如何设计出和 ASP.NET Core 中 Middleware 一样的 API 方法?
由于笔者时间有限,无法写更多的说明文本,且主要是自己用来记录学习点滴,请谅解,下面直接贴代码了(代码中有一些说明): 01-不好的设计 代码: using System; namespace Desi ...
- spring boot 2 集成JWT实现api接口认证
JSON Web Token(JWT)是目前流行的跨域身份验证解决方案.官网:https://jwt.io/本文使用spring boot 2 集成JWT实现api接口验证. 一.JWT的数据结构 J ...
- ASP.NET Core 3.0 WebApi中使用Swagger生成API文档简介
参考地址,官网:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view ...
- EF Core中通过Fluent API完成对表的配置
EF Core中通过Fluent API完成对表的配置 设置实体在数据库中的表名 通过ToTable可以为数据模型在数据库中自定义表名,如果不配置,则表名为模型名的复数形式 public class ...
- ASP.NET Core系列:JWT身份认证
1. JWT概述 JSON Web Token(JWT)是目前流行的跨域身份验证解决方案. JWT的官网地址:https://jwt.io JWT的实现方式是将用户信息存储在客户端,服务端不进行保存. ...
随机推荐
- networkx整理
1.基础知识 1.1.介绍 networkx在2002年5月产生,是一个用Python语言开发的图论与复杂网络建模工具,内置了常用的图与复杂网络分析算法,可以方便的进行复杂网络数据分析.仿真建模等工作 ...
- Hibernate 查询方式、JPA查询方式
hibernate 查询方式: OID 查询 对象导航查询 HQL 方式查询 QBC方式查询 原生SQL方式查询 JPA 查询方式: OID 查询 对象导航查询 JPQL 方式查询 CriteriaB ...
- NOIP提高组/CSP-S复赛需掌握的算法
1.排序算法(快排.选择.冒泡.堆排序.二叉排序树.桶排序) 2.DFS/BFS 也就是搜索算法,剪枝务必要学! 学宽搜的时候学一下哈希表! 3.树 ①遍历 ②二叉树 ③二叉排序树(查找.生成.删除) ...
- 【长期维护】C++休闲(修仙)躲方块小游戏
左右键控制小球左右移动,上键加速,Esc退出. 一个‘@’20分 #include <windows.h> #include <bits/stdc++.h> #include ...
- 地精部落:dp
Description 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi, ...
- 详谈Generator
Generator究竟有什么样的作用呢???? 他是ES6提出的一个解决异步问题方案 先看一段代码, 感受一下generator函数和普通函数的区别 function* test(){ yield 2 ...
- NOIP模拟测试19考试反思
这次考试是存在很大问题的,(如果不是T1T2出乎意料地A了,鬼知道会发生什么) T2A是情理之中,考试的时候测的极限数据跑的很快(无论m什么范围),但是T1真的...... T3没有分配太多的时间+没 ...
- Java基础语法03-数组
四数组 数组概念: 数组就是用于存储数据的长度固定的容器,多个数据的数据类型要一致. 百科:数组(array),就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,以 ...
- Windows下Apache与PHP的安装与配置
下载Apache Apache的官网(http://httpd.apache.org) 1.把解压后的Apache拷贝到要安装的目标位置.建议拷贝到C盘根目录下,因为这是其默认设置. 2.我选择的是拷 ...
- 【SSM Spring 线程池 OJ】 使用Spring线程池ThreadPoolTaskExecutor
最近做的Online Judge项目,在本地判题的实现过程中,遇到了一些问题,包括多线程,http通信等等.现在完整记录如下: OJ有一个业务是: 用户在前端敲好代码,按下提交按钮发送一个判题请求给后 ...