Encapsulation and use of JWT in ASP .NET Core

JWT principle:

JWT principle

Configuring JWT

(1) Write the JWT configuration node, and create two configuration items SecKey and ExpireSeconds under the node, which represent the key and expiration time of the JWT respectively (I configured it here in appsettings.json, the expiration time unit is seconds, you can adjust it according to your own situation choose)

(1) Create a configuration class, including two properties: SecKey (key) and ExpireSeconds (expiration time) (such as JWTOptions class, names, etc. do not need to be the same) to facilitate us to read the configuration

public class JWTOptions
{<!-- -->
    public string SecKey {<!-- --> get; set; }
    public int ExpireSeconds {<!-- --> get; set; }
}

(2)Nuget:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

(3) Register JWT. After registration, if there is Authorization in the message header, it will automatically parse and verify the JWT token for us. If the accessed Action method has the Authorize attribute, access can only be accessed if the verification is successful.

//Register the configuration and bind the configuration to the corresponding real column so that it can be called by other places. For example, I use it here when generating JWT tokens.
builder.Services.Configure<JWTOptions>(builder.Configuration.GetSection("JWT"));
//Register JWT
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).
     AddJwtBearer(option =>
     {<!-- -->
         //Do some JWT configuration inside, for JWT configuration
         //Read some JWT data again, read the key, etc., and verify
         JWTOptions jwtOptions = builder.Configuration.GetSection("JWT").Get<JWTOptions>();
         byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOptions.SecKey);
         var secKey = new SymmetricSecurityKey(keyBytes);
         option.TokenValidationParameters = new()
         {<!-- -->
             ValidateIssuer = false,
             ValidateAudience = false,
             ValidateLifetime = true,
             ValidateIssuerSigningKey = true,
             IssuerSigningKey = secKey
         };

     });

Generate JWT token

(1) Add app.UseAuthentication() before this line of code in app.UseAuthorization() of Program.cs
Authentication and authorization verification functions in ASP.NET Core are provided by Authentication and Authorization middleware

This step is very important, otherwise Asp.Net Core will not help us automatically verify the JWT token when we access the Action method with the attribute [Authorize] added.

app.UseAuthentication();//Add app.UseAuthentication() before app.UseAuthorization
app.UseAuthorization();

(2) Generate a JWT token and return it to the client (see the JWT principle at the beginning for details)

[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{<!-- -->
    //Set interface call configuration
    private readonly IOptionsSnapshot<JWTOptions> optionsSnapshot;
    public ValuesController(IOptionsSnapshot<JWTOptions> optionsSnapshot)
    {<!-- -->
        this.optionsSnapshot = optionsSnapshot;
    }

    /// <summary>
    /// To obtain the JWT token, generally speaking, you first determine whether the token has been passed. If not, you need to check whether there is the user. If the token is created, it will be returned. If there is no user, it will be returned. Change the article to only focus on JWT. I won’t write it here.
    /// My abbreviation here
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public async Task<ActionResult<string>> ReturnJWT(string name, string password)
    {<!-- -->
        string jwt = string.Empty;
        if (name == "Passion Fruit" & amp; & amp; password == "123456")
        {<!-- -->
            //generate token
            List<Claim> claims = new List<Claim>();
            claims.Add(new Claim(ClaimTypes.Name, name));
            claims.Add(new Claim(ClaimTypes.Role, "admin"));
            //Read the configuration to get the key
            string key = optionsSnapshot.Value.SecKey;
            //Set the expiration time, which means when will the jwt sent to you expire?
            DateTime expire = DateTime.Now.AddSeconds(optionsSnapshot.Value.ExpireSeconds);//Set the expiration time
                                                                                               
            byte[] secBytes = Encoding.UTF8.GetBytes(key);
            var secKey = new SymmetricSecurityKey(secBytes);
            var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
            var tokenDescriptor = new JwtSecurityToken(claims: claims,
                expires: expire, signingCredentials: credentials);
            jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
        }
        return jwt;
    }
}

Carry JWT token to access the corresponding Action method

Note: We do not need to write the code to parse the JWT token ourselves. When we access the Action method that can only be accessed by logging in, we previously passed builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).
The service registered with AddJwtBearer(…) will automatically verify it for us. If it is correct, you can access the Action method, otherwise, vice versa.

The requirement is that the server needs to add the Authorize feature to the Action method of verifying the JWT token, and the client needs to add the Authorization value of “Bearer JWTToken (JWT token)” to the message header for access. (The value of Authorization is
“Bearer” and the JWT token must be separated by spaces, and there must be no extra spaces, line breaks, etc.), as follows:

(1) Add [Authorize] to the controller class or Action method that requires login to access (if placed on the controller, it will take effect for all Action methods in the controller, otherwise it will only take effect for the specified Action method, and only login to access these methods)

(2) When accessing again, define Authorization in the message header based on the JWT token passed to the client when logging in. Access the Action method with the attribute [Authorize] added, and then automatically verify the JWT token based on the registered service. , if the verification is successful, you can access the Action method that requires login, and put the plain text data in User for us to call. Without adding [Authorize], you can access without logging in. You only need to know the address. That’s it

Postman Visit:

[Route("api/[controller]/[action]")]
[ApiController]
[Authorize]
public class AuthorizeController : ControllerBase
{<!-- -->
    /// <summary>
    /// Get the clear text information passed during login in the JWT token passed
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public string GetInfo()
    {<!-- -->
        //When the token is passed, you can obtain the clear text information passed in the token when logging in. You can use the following method
        var name = this.User.FindFirst(ClaimTypes.Name)!.Value;
        var roles = this.User.FindAll(ClaimTypes.Role);
        string roleStr = string.Join(",", roles.Select(c => c.Value));

        return name + "|" + roleStr;
    }
    /// <summary>
    /// The following method does not require verification, just add the AllowAnonymous attribute
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [AllowAnonymous]
    public string GetInfo1()
    {<!-- -->
        return "111";
    }
}