在.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的实现方式是将用户信息存储在客户端,服务端不进行保存. ...
随机推荐
- 条件渲染vue
v-if:只渲染一次的情况下,性能更好v-show:频繁切换性能更好 vue虚拟DOM技术 浏览器:渲染引擎(慢)+JS引擎(快) 用1个JS对象来充当DOM对象,因为JS对象性能比较快,所以用虚拟D ...
- 设计模式C++描述----18.中介者(Mediator)模式
一. 举例 比如,现在中图和日本在关于钓鱼岛问题上存在争端.这时,联合国就会站出来,做为调解者,其实也没什么好调解的,钓鱼岛本来就是中国的,这是不争的事实!联合国也就是个传话者.发言人. 结构图如下: ...
- ios Autolayout 按比例相对布局
看到一篇讲ios storyboard 按比例相对布局的博客,挺不错的转下来了! 可到liumh.com查看. 本文记录如何在 UIStoryboard 或者 xib 中进行百分比布局,包括 View ...
- 【C#多线程】1.Thread类的使用及注意要点
Thread随便讲讲 因为在C#中,Thread类在我们的新业务上并不常用了(因为创建一个新线程要比直接从线程池拿线程更加耗费资源),并且在.NET4.0后新增了Task类即Async与await关键 ...
- Appium的加载过程
appium运行流程 Appium的加载过程如上图. 1)调用Android adb完成基本的系统操作: 2)向Android上部署bootstrap.jar: 3)Bootstrap.jar For ...
- csps63总结
这次考试还算可以(吧),暴力都没打满,但是还差很多. T1 强烈推荐我的打法,很好理解并且很好打(虽然稍长) 维护指针指向的值及其是第几个数,然后分类讨论. (诡异构造的序列==随机数据)?? #in ...
- vue引入百度地图 --BMap is not defined ,eslint BMap报错
在mounted初始化地图的时候,因为异步问题会导致BMap is not defined,也就是百度的api还没完全引入或者加载完成,就已经进行地图初始化了 解决方法: 1.创建一个map.js e ...
- 从代码的视角深入浅出理解DevOps
对于DevOps的理解大家众说纷纭,就连维基百科(Wikipedia)都没有给出一个统一的定义.一般的解释都是从字面上来理解,就是把开发(Development)和运维(Operations)整合到一 ...
- vue 单页面应用 app自适应方案
本文是使用淘宝的方案进行布局开发的,遇到的问题是会对app内使用的第三方插件,当页面进行缩放后,比如高德地图中的文字会显得过小,我使用的方法就是手动的动每一个尺寸进行手动的px 到 rem的替换,而不 ...
- Subline Text3最新激活方法解决 That license key doesn't appear to be valid.
第一步: 管理员身份登录系统 第二步: 进入到 C:\Windows\System32\drivers\etc (这个路径可以复制,都是一样的) 第三步: 右键hosts这个文件(打开方式 - 选择记 ...