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();
    }
  }

Related articles: