.
: Header , Payload , Signature and usually looks like this aaaaaaa.bbbbbb.cccccc
. More information can be found at jwt.io or RFC 7519 .{ "alg": "HS256", "typ": "JWT" }
{ "email": "temp@jwt.ru", "user_id": "57dc51a3389b30fed1b13f91" }
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
project.json
file: "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", "Microsoft.AspNetCore.Mvc.Core": "1.0.0", "Microsoft.AspNetCore.Mvc.Formatters.Json": "1.0.0"
Microsoft.AspNetCore.Mvc.Core
assembly instead of Microsoft.AspNetCore.Mvc
in order not to drag unnecessary (for our rest service) dependencies in the form of Razor , TagHelper , etc.Startup.cs
file, slightly correcting it: public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvcCore(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseMvc().UseMvcWithDefaultRoute(); } }
Startup.cs
and add the following: public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvcCore() .AddAuthorization(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { var key = Encoding.UTF8 .GetBytes("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"); var options = new JwtBearerOptions { TokenValidationParameters = { ValidIssuer = "ExampleIssuer", ValidAudience = "ExampleAudience", IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuerSigningKey = true, ValidateLifetime = true, ClockSkew = TimeSpan.Zero } }; app.UseJwtBearerAuthentication(options); app.UseMvcWithDefaultRoute(); } }
ConfigureServices
method, everything is pretty obvious, we add the use of the authorization service, and also register the HttpContextAccessor
. For what we needed explicit registration HttpContextAccessor, we will find out a little later. Let us turn to the Configure
method, in which the parameters are set up to validate the JWT token. Now, we are most interested in three parameters:IssuerSigningKey
is the key with which our token should be signed. For example, choose SymmetricSecurityKey , but you can also specify X509SecurityKey () or JsonWebKey if you have a lot of love for JSON.ValidateIssuerSigningKey
- we indicate that we will verify the key with which the JWT token was signed.ValidateLifetime
- set to true , because we want to control the lifetime of the token.HomeController.cs
controller: [Route("/")] public class HomeController { private readonly IHttpContextAccessor _context; public HomeController(IHttpContextAccessor context) { _context = context; } [HttpGet("token")] public dynamic GetToken() { var handler = new JwtSecurityTokenHandler(); var sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"; var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(sec)); var signingCredentials = new SigningCredentials(securityKey,SecurityAlgorithms.HmacSha256Signature); var identity = new ClaimsIdentity(new GenericIdentity("temp@jwt.ru"), new[] { new Claim("user_id", "57dc51a3389b30fed1b13f91") }); var token = handler.CreateJwtSecurityToken(subject: identity, signingCredentials: signingCredentials, audience: "ExampleAudience", issuer: "ExampleIssuer", expires: DateTime.UtcNow.AddSeconds(42)); return handler.WriteToken(token); } [Authorize, HttpGet("secure")] public dynamic Secret() { var currentUser = _context.HttpContext.User; return currentUser.Identity.Name; } }
AspNetCore.Mvc.Core
, the only way (although there may be another one) is to get to HttpContext - just through IHttpContextAccessor
, which we registered earlier.signingCredentials
- we create a key with which we sign our token, it should be the same as the one we specified in Startup.cs
when setting up JWT parameters.identity
- create our payload
. Of course, in a real application we will get data from the repository, having checked them before, and now we will build some hardcode.expires: DateTime.UtcNow.AddSeconds(42)
, rather trivial and flexible. curl -X GET "http://localhost:<your_port>/token"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InRlc3RAdGVzdC5ydSIsInVzZXJfaWQiOiI1N2RjNTFhMzM4OWIzMGZlZDFiMTNmOTEiLCJuYmYiOjE0NzQyMTU4MDAsImV4cCI6MTQ3NDIxNTgzNSwiaWF0IjoxNDc0MjE1ODAwLCJpc3MiOiJFeGFtcGxlSXNzdWVyIiwiYXVkIjoiRXhhbXBsZUF1ZGllbmNlIn0.9NhOkoalaE70nIb-erH_waWx8rk6QJta5N19EiBLETQ
curl -X GET "http://localhost:<your_port>/secure"
401 Unauthorized
will be returned, as expected. curl -X GET -H "Authorization: Bearer token_should_be_here" "http://localhost:<your_port>/secure"
GenericIdentity
.401 Unauthorized
and the WWW-Authenticate
header will have the value: Bearer error="invalid_token", error_description="The token is expired"
telling us about expired token.blacklist
that will contain invalid tokens. But now we still have to make an extra request to check our token.refresh
- a token for a longer time. Not a beautiful decision in my opinion.Source: https://habr.com/ru/post/311594/
All Articles