Adding user claims

The JWT we created has an empty payload so far and carries no meaningful information. And even though it's enough to make sure that the user has been authenticated by simply validating that the token was signed by the server key, we wouldn't be able to know anything about the authenticated user. 

Claims allow us to add key-values pairs that we can later retrieve from the token. For example, the GiveNTake application adds the user email as a claim, and then uses it to retrieve the User entity from the database when needed. 
Here is how the GenerateTokenAsync method can be modified to include all the user claims:

private async Task<JwtSecurityToken> GenerateTokenAsync(User user)
{
var claims = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.UserName),
};


var token = new JwtSecurityToken
(
claims: claims,

//... the rest of initalization
);

return token;
}

The JWT RFC document (https://tools.ietf.org/html/rfc7519) specifies a set of standard claims that can be included inside the JWT, such as the Subject (sub) and JWT ID (jit), and there are other claim types, such as name identifier, that are parts of the SAML standard. For your convenience, the JwtRegisteredClaimNames and ClaimTypes static classes contain static members that allow you to easily add those claims to your token. Beside the standard claim types, you can added whatever key-value pairs you wish.

If you run the application again and successfully log in, you should see that the token is considerably bigger than it was before:

The text in this image is not important; you may get different values. The purpose of this image is to show you what the structure of the request and response should look like in Postman.
You can debug the JWT and see its claims by pasting it to the JWT debugger, available at http://jwt.io.

Save the token so that we can use it later.

To test your token, let's add an API that will allow the client application to retrieve the logged-in user's email address. Add the following method to your AccountController:

[Authorize]
[HttpGet("Email")]
public ActionResult<string> GetEmail()
{
return Ok(User.Identity.Name);
}

The Authorize attribute is the way we specify to the request pipeline that this method can only be used by authenticated users. When a request is received from an authenticated user (which means that a valid token is included with it), the authentication middleware extracts the user information and initializes the controller's User property, which is of the System.Security.Claims.ClaimsPrincipal type, that implements the System.Security.Principal.IPrincipal interface. The identity property of the IPrincipal interface allows you to retrieve the identity of the user, including their username, which is the user's email address in our case.

You can use [Authorize] on the method level as well as on the controller class level. When the controller is decorated with the [Authorize] attribute, the authorization check will be applied on all the API actions contained in the class.

Create a new HTTP GET request in Postman to the URL http://localhost:{port}/api/account/email. Add a new Authorization header to your request and set it to Bearer [token value], like this: 

Execute the request and you'll see that the user email address has been returned:

The text in this image is not important; you may get different values. The purpose of this image is to show you what the structure of the request and response should look like in Postman.
Bearer is the authentication schema associated with the JWT. By specifying Bearer in the authorization header, we made it possible for the backend to understand that a JWT was sent, and therefore, the JWT middleware will be activated in the request pipeline.

With this technique, we can now make the necessary adjustment to make sure that added products are registered under their seller:

[Authorize]
[HttpPost("")]
public async Task<ActionResult<ProductDTO>> AddNewProduct([FromBody] NewProductDTO newProduct)
{
// ...

var user = await _context.Users.FindAsync(User.Identity.Name);
var product = new Product()
{
Owner = user,
Category = category,
Title = newProduct.Title,
Description = newProduct.Description,
City = city,
PublishDate = DateTime.UtcNow
};
_context.Products.Add(product);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetProduct),
new { id = product.ProductId },
_productsMapper.Map<ProductDTO>(product));
}

The AddNewProduct method is now decorated with the Authorize attribute to make sure that only authenticated users can call it. This method loads the User entity by the ID that is encapsulated in the current user identity.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.116.137