ASP. NET Core Authentication Authorization Method Using JWT
- 2021-11-14 05:28:55
- OfStack
demo Address: https://github.com/william0705/JWTS
Noun parsing
Authentication: Identify whether the user is legal or not
Authorization: Give users permissions (which resources can be accessed)
Authentication: Authenticate whether the authority is legal
Advantages and disadvantages of Jwt
Advantage
1. Stateless
token stores all authentication information, the server does not need to save user authentication information, reducing the pressure on the server, and the server is easier to expand horizontally. Because of statelessness, it will lead to its biggest disadvantage and it is difficult to log out
2. Support cross-domain access
Cookie does not allow out-of-domain access, and token supports
3. Cross-language
Based on the standardized JSON Web Token (JWT), it does not depend on a specific language. For example, the generated Token can be used in multiple languages (Net, Java, PHP …)
Disadvantage
1. Token effectiveness problem
It is very difficult to unregister the published Token in the background, and it is usually necessary to use the third-party storage (database/cache) to unregister, which will lose the biggest advantage of JWT
2. Bandwidth occupied
The length of Token (depending on the stored content) is larger than that of session_id, and each request consumes more bandwidth. token only stores necessary information to avoid token being too long
3. Renewal is required
cookies session is usually the framework has implemented the renewal function, each access to update the expiration time, JWT needs to be implemented by itself, refer to OAuth2 refresh Token mechanism to refresh Token
4. Consuming more CPU
Each request requires two steps: decrypting the content and verifying the signature. Typically, time is exchanged for space
You can only decide which authentication scheme to use according to your own usage scenario, and none of them is universal and perfect
. NET Core Integrated JWT Authentication and Authorization Service
1. Authentication Service API: Authenticate users and publish Token
1. Introduce nuget package, System. IdentityModel. Tokens. Jwt
2. Create services that generate Token. It is recommended to use interface-oriented and implementation-oriented programming to facilitate service injection container ServicesCollection (involving DI and IOC concepts)
3. Create an interface
namespace JWTS.Services
{
public interface IJWTService
{
/// <summary>
/// Generated according to the users and roles after verification Token, To achieve the role control
/// </summary>
/// <param name="userName"></param>
/// <param name="role"></param>
/// <returns></returns>
string GetToken(string userName,string role);
}
}
4. Add the information needed to generate token in appsettings. config and map it to an object
"TokenParameter": {
"Issuer": "William", // This JWT Issuing subject of ( Publisher )
"Audience": "William", // This JWT Receive object of
"SecurityKey": "askalsnlkndhasnaslkasmadka"
}
public class TokenParameter
{
public string Issuer { get; set; }
public string Audience { get; set; }
public string SecurityKey { get; set; }
}
5. Implement interface, inject Configuration, and obtain TokenParameter object
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace JWTS.Services
{
public class JWTService : IJWTService
{
private readonly TokenParameter _tokenParameter;
public JWTService(IConfiguration configuration)
{
_tokenParameter = configuration.GetSection("TokenParameter").Get<TokenParameter>();
}
/// <summary>
/// JWT By 3 Part composition ( Header , Payload , Signature )
/// {Header}.{Payload}.{Signature}
/// </summary>
/// <param name="userName"></param>
/// <param name="role"></param>
/// <returns></returns>
public string GetToken(string userName,string role)
{
Claim[] claims = new[]
{
new Claim(ClaimTypes.Name, userName),
new Claim("NickName","Richard"),
new Claim("Role",role)// Pass on other information
};
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenParameter.SecurityKey));
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
/**
* Claims (Payload)
Claims Section contains 1 Something to do with this token Important information about. JWT The standard stipulates that 1 Some fields, excerpts below 1 Some fields :
JWT Will be encrypted, but this part of the content can be read by anyone, so don't store confidential information
iss: The issuer of the token , token Who is it for
sub: The subject of the token , token Theme
exp: Expiration Time . token Expired time, Unix Timestamp format
iat: Issued At . token Creation time, Unix Timestamp format
jti: JWT ID . For the current token The only 1 Identification
In addition to the specified fields, you can contain any other JSON Compatible fields.
* */
var token = new JwtSecurityToken(
issuer: _tokenParameter.Issuer,
audience: _tokenParameter.Audience,
claims: claims,
expires: DateTime.Now.AddMinutes(10),//10 Minute validity period
signingCredentials: creds);
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
return returnToken;
}
}
}
6. Claims as defined in jwt
The claim specified in the JWT standard are:
iss (Issuser): Represents the issuing entity of this JWT; sub (Subject): Represents the body of this JWT, that is, its owner; aud (Audience): Represents the receiving object of this JWT; exp (Expiration time): Is a timestamp representing the expiration time of this JWT; nbf (Not Before): is a timestamp representing the start time when this JWT is effective, which means that it will fail to verify JWT before this time; iat (Issued at): Is a timestamp representing the time when this JWT was issued; jti (JWT ID): Is the only identification of JWT.7. In the authentication project Startup. cs file, dependency injects the service class of JWT
public void ConfigureServices(IServiceCollection services) { services.AddScoped <IJWTService, JWTService> (); services.AddControllers(); }
8. AuthenticationController is added to generate Token, and RefreshToken can be added later
using JWTS.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace JWTS.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthenticationController : ControllerBase
{
#region Constructor
private ILogger<AuthenticationController> _logger;
private IJWTService _iJWTService;
private readonly IConfiguration _iConfiguration;
public AuthenticationController(ILogger<AuthenticationController> logger,
IConfiguration configuration
, IJWTService service)
{
_logger = logger;
_iConfiguration = configuration;
_iJWTService = service;
}
#endregion
/// <summary>
/// Actual scenario use Post Method
/// http://localhost:5000/api/Authentication/Login?name=william&password=123123
/// </summary>
/// <param name="name"></param>
/// <param name="password"></param>
/// <returns></returns>
[Route("Login")]
[HttpGet]
public IActionResult Login(string name, string password)
{
// Here should be the need to connect to the database to do data verification, in order to facilitate all user names and passwords written dead
if ("william".Equals(name) && "123123".Equals(password))// Should database
{
var role = "Administrator";// You can get roles from the database
string token = this._iJWTService.GetToken(name, role);
return new JsonResult(new
{
result = true,
token
});
}
return Unauthorized("Not Register!!!");
}
}
}
2. Resource Center API: Access the resource by using Token obtained from the Authentication Service Center. The Resource Center authenticates the user information and Token, and returns 401 if the authentication fails
1. Add Nuget package to resource center (Microsoft. AspNetCore. Authentication. JwtBearer)
2. Add Authentication service, add JwtBearer, and obtain TokenParameter object through Configuration
using System;
using System.Text;
using API.Core.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
namespace API.Core
{
public class Startup
{
private TokenParameter _tokenParameter;
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
_tokenParameter = configuration.GetSection("TokenParameter").Get<TokenParameter>()??throw new ArgumentNullException(nameof(_tokenParameter));
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)// Default authorization mechanism
.AddJwtBearer(options =>
{
options.TokenValidationParameters=new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _tokenParameter.Issuer,
ValidAudience = _tokenParameter.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenParameter.SecurityKey))
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
3. Add the [Authorize] attribute on the resource controller to enable authentication authorization to access API resources
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}