JWT(Json Web Token) is not necessary to introduce too much. It is also common to use JWT for authentication in.NET Core development, and the access process is relatively simple. You can configure it casually.

To use JWT, you only need to reference one of Microsoft’s certification components in your project.

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Copy the code

Some sensitive data can then be placed in the configuration file AppSettings. json.

{
    "JWT": {
        "ClockSkew": 10."ValidAudience": "https://meowv.com"."ValidIssuer": "Star Plus"."IssuerSigningKey": "6Zi/5pifUGx1c+mYv+aYn1BsdXPpmL/mmJ9QbHVz6Zi/5pifUGx1c+mYv+aYn1BsdXPpmL/mmJ9QbHVz6Zi/5pifUGx1c+mYv+aYn1BsdXPpmL/mmJ9QbHV z6Zi/5pifUGx1cw=="."Expires": 30}}Copy the code

Add the configuration in Startup and use it

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(Convert.ToInt32(Configuration.GetSection("JWT") ["ClockSkew"])),
                ValidateIssuerSigningKey = true,
                ValidAudience = Configuration.GetSection("JWT") ["ValidAudience"],
                ValidIssuer = Configuration.GetSection("JWT") ["ValidIssuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("JWT") ["IssuerSigningKey"))}; }); services.AddAuthorization();Copy the code
app.UseAuthentication();
app.UseAuthorization();
Copy the code

With this simple JWT configuration done, a new interface is written to generate tokens.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace JsonWebTokenDemo.Controllers{[Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        public AuthController(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        [HttpGet]
        [Route("Token")]
        public string GenerateTokenAsync(string username, string password)
        {
            if (username == "meowv" && password == "123")
            {
                var claims = new[] {
                    new Claim(ClaimTypes.Name, username),
                    new Claim(ClaimTypes.Email, "[email protected]"),
                    new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(Convert.ToInt32(Configuration.GetSection("JWT") ["Expires"]))).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")};var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("JWT") ["IssuerSigningKey"]));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                var securityToken = new JwtSecurityToken(
                    issuer: Configuration.GetSection("JWT") ["ValidIssuer"],
                    audience: Configuration.GetSection("JWT") ["ValidAudience"],
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(Convert.ToInt32(Configuration.GetSection("JWT") ["Expires"])),
                    signingCredentials: creds);

                var token = new JwtSecurityTokenHandler().WriteToken(securityToken);

                return token;
            }
            else
            {
                throw new Exception("Incorrect account password"); }}}}Copy the code

After a successful login, the token is generated. In actual applications, a third-party login system can be connected for authentication, and the interface can be invoked to check the effect.

As you can see, the first interface successfully returns the token by entering the correct account password, and the second interface throws an exception.

Next, write two interfaces to verify the normal use of token. Write an interface that requires authorization and an interface that does not need authorization.

[HttpGet]
[Authorize]
[Route("AuthorizeTest")]
public string AuthorizeTest()
{
    return "I'm returning results.";
}

[HttpGet]
[AllowAnonymous]
[Route("AllowAnonymousTest")]
public string AllowAnonymousTest()
{
    return "I'm returning results.";
}
Copy the code

The only difference between these two interfaces is that [Authorize] and [AllowAnonymous].

Add [Authorize] to indicate that authorization is required to access the interface. Add [AllowAnonymous] to indicate that no authorization is required to access the interface.

The first interface did not return the result, so it took effect. At this time, the data can be returned only after the token we generated before is successfully authorized when the call is made.

Sometimes when we fail to authorize, we will return an error page for 401. What if we need to customize the return message?

There are several ways to do this, using middleware, interceptors, etc., but a good component integration approach is to go directly to the code.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            ...

            options.Events = new JwtBearerEvents
            {
                OnChallenge = async context =>
                {
                    context.HandleResponse();

                    context.Response.ContentType = "application/json; charset=utf-8";
                    context.Response.StatusCode = StatusCodes.Status401Unauthorized;

                    await context.Response.WriteAsync("{\"message\":\"Unauthorized\",\"success\":false}"); }}; });Copy the code

Add the code above, await the context. The Response. The WriteAsync () can return to your custom error messages, here is a json string.

If I do not want to use token in my request headers, what do I do if I do not want to use token in my request headers? Say I want to put the token in the URL parameter, or in the cookie?

It’s also possible, and it’s super easy to implement. Look at the code below.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            ...

            options.Events = new JwtBearerEvents
            {
                ...
                OnMessageReceived = async context =>
                {
                    context.Token = context.Request.Query["token"];

                    awaitTask.CompletedTask; }}; });Copy the code

The token is shown here in the URL request parameters, other cases can be modified according to the actual development scenario.