/jwt.netTutorial

JSON Web Token is a proposed Internet standard for creating data with optional signature and/or optional encryption whose payload holds JSON that asserts some number of claims. The tokens are signed either using a private secret or a public/private key.

Primary LanguageC#

JWT Basics

Getting started with Json-Web-Token

  1. Create two folders

    1. backend

      1. Controllers

        1. ProductsController

          1. INDEX

          2. DETAILS

          3. CREATE

          4. EDIT

          5. DELETE

      2. Migrations

      3. Models

        1. Product.cs

        2. ProductManagement.cs

    2. frontend

      1. Controllers

        1. ProductsController

          1. INDEX

          2. CREATE

          3. EDIT

          4. DELETE

      2. Model

        1. Product.cs
      3. Views

        1. Create.cshtml

        2. Delete.cshtml

        3. Edit.cshtml

        4. Index.cshtml

  2. To Start

    1. backend

    2. frontend

  3. Screenshots

backend

This will contain webapi from the project

Controllers

ProductsController.cs

INDEX

[Authorize(Roles = "Admin,User")]
[HttpGet]
public IEnumerable<Product> Get()
{
    return productManagementDbContext.Products.ToList();
}

Authorize validates token to check for user or admin

DETAILS

[HttpGet("{id}")]
public Product Get(int id)
{
    return this.productManagementDbContext.Products.Where(product => product.Id == id).FirstOrDefault();
}

CREATE

[HttpPost]
public string Post([FromBody] Product product)
{
    this.productManagementDbContext.Products.Add(product);
    this.productManagementDbContext.SaveChanges();
    return "Product created successfully!";
}

EDIT

[HttpPut("{id}")]
public void Put(int id, [FromBody] Product product)
{
    this.productManagementDbContext.Products.Update(product);
    this.productManagementDbContext.SaveChanges();
}

DELETE

[HttpDelete("{id}")]
public void Delete(int id)
{
    this.productManagementDbContext.Products.Remove(this.productManagementDbContext.Products.Where(product => product.Id == id).FirstOrDefault());
    this.productManagementDbContext.SaveChanges();
}

Migrations

This will contail entity framework files for database integration.

Models

Product.cs

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Price { get; set; }
}

ProductManagement.cs

public ProductManagementDbContext(DbContextOptions<ProductManagementDbContext> dbContextOptions) : base(dbContextOptions)
{
}
public DbSet<Product> Products { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().HasData(
        new User { Id = 1, Email = "admin@gmail.com", Password = "Passcode1", Role = Roles.Admin },
        new User { Id = 2, Email = "user@gmail.com", Password = "Passcode2", Role = Roles.User }
        );
}

frontend

This will contain mvc from the project

Controllers

ProductsController.cs

INDEX

private static HttpClient httpClient = new HttpClient();
public ProductsController(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }
// GET: /<controller>/
[HttpGet]
public async Task<IActionResult> Index()
{
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", HttpContext.Session.GetString("token"));
    var response = await httpClient.GetAsync(Configuration.GetValue<string>("WebAPIBaseUrl") + "/products");
    var content = await response.Content.ReadAsStringAsync();
    if (response.IsSuccessStatusCode)
    {
        var products = new List<Product>();
        if (response.Content.Headers.ContentType.MediaType == "application/json")
        {
            products = JsonConvert.DeserializeObject<List<Product>>(content);
        }
        return View(products);
    }
    else
    {
        return RedirectToAction("Login", "Account");
    }
}

CREATE

public async Task<IActionResult> Create()
{
    return View();
}

[HttpPost]
public async Task<IActionResult> Create(Product product)
{
    if (ModelState.IsValid)
    {
        var serializedProductToCreate = JsonConvert.SerializeObject(product);
        var request = new HttpRequestMessage(HttpMethod.Post, Configuration.GetValue<string>("WebAPIBaseUrl") + "/products");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Content = new StringContent(serializedProductToCreate);
        request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        var response = await httpClient.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            return RedirectToAction("Index", "Products");
        }
        else
        {
            ViewBag.Message = "Admin access required";
            return View("Create");
        }
    }
    else
        return View("Create");
}

EDIT

[HttpGet]
public async Task<IActionResult> Edit(int id)
{
    var response = await httpClient.GetAsync(Configuration.GetValue<string>("WebAPIBaseUrl") + $"/products/{id}");
    response.EnsureSuccessStatusCode();
    var content = await response.Content.ReadAsStringAsync();
    var product = new Product();
    if (response.Content.Headers.ContentType.MediaType == "application/json")
    {
        product = JsonConvert.DeserializeObject<Product>(content);
    }
    return View(product);
}

[HttpPost]
public async Task<IActionResult> Edit(Product product)
{
    if (ModelState.IsValid)
    {
        //httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", HttpContext.Session.GetString("token"));
        var serializedProductToEdit = JsonConvert.SerializeObject(product);
        var request = new HttpRequestMessage(HttpMethod.Put, Configuration.GetValue<string>("WebAPIBaseUrl") + $"/products/{product.Id}");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Content = new StringContent(serializedProductToEdit);
        request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        var response = await httpClient.SendAsync(request);
        if (response.IsSuccessStatusCode)
        {
            return RedirectToAction("Index", "Products");
        }
        else
        {
            ViewBag.Message = "Admin access required";
            return View("Edit");
        }
    }
    else
        return View("Edit");
}

DELETE

[HttpGet]
public async Task<IActionResult> Delete(int id)
{
    var response = await httpClient.GetAsync(Configuration.GetValue<string>("WebAPIBaseUrl") + $"/products/{id}");
    response.EnsureSuccessStatusCode();
    var content = await response.Content.ReadAsStringAsync();
    var product = new Product();
    if (response.Content.Headers.ContentType.MediaType == "application/json")
    {
        product = JsonConvert.DeserializeObject<Product>(content);
    }
    return View(product);
}

[HttpPost]
public async Task<IActionResult> Delete(Product product)
{
    if (ModelState.IsValid)
    {
        //httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", HttpContext.Session.GetString("token"));
        var serializedProductToDelete = JsonConvert.SerializeObject(product);
        var request = new HttpRequestMessage(HttpMethod.Delete, Configuration.GetValue<string>("WebAPIBaseUrl") + $"/products/{product.Id}");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Content = new StringContent(serializedProductToDelete);
        request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        var response = await httpClient.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            return RedirectToAction("Index", "Products");
        }
        else
        {
            ViewBag.Message = "Admin access required";
            return View("Delete");
        }
    }
    else
        ViewBag.Message = "wrong";
    return View("Delete");
}

Models

Product.cs

    public class Product
    {
        public Product()
        {
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public int Price { get; set; }
    }

Views

Create.cshtml

@{
    ViewBag.Title = "Create";
}
@model Product
<form asp-action="Create" asp-controller="Products" method="post" class="contactForm">
    <fieldset>
        <p>
            <label asp-for="Name"></label>
            <input asp-for="Name" />
        </p>
        <p>
            <label asp-for="Price"></label>
            <input asp-for="Price" />
        </p>
        <p>
            <button type="submit" class="btn btn-primary">Save</button>
        </p>
    </fieldset>
        <h6 style="color:red">@Html.Raw(@ViewBag.Message)</h6>
 
</form>

Delete.cshtml

@{
    ViewBag.Title = "Delete - " + @Model.Name;
}
@model Product

<form asp-action="Delete" asp-controller="Products" method="post" class="contactForm">
    <fieldset>
        <p>
            <input asp-for="Id" hidden readonly />
        </p>
        <p>
            <label asp-for="Name"></label>
            <input asp-for="Name" />
        </p>
        <p>
            <label asp-for="Price"></label>
            <input asp-for="Price" />
        </p>
        <p>
            <button type="submit" class="btn btn-danger">Delete</button>
        </p>
    </fieldset>
    <h6 style="color:red">@Html.Raw(@ViewBag.Message)</h6>
</form>

Edit.cshtml

@{
    ViewBag.Title = "Edit - " + @Model.Name;
}
@model Product

<form asp-action="Edit" asp-controller="Products" method="post" class="contactForm">
    <fieldset>
        <p>
            <input asp-for="Id" hidden readonly />
        </p>
        <p>
            <label asp-for="Name"></label>
            <input asp-for="Name" />
        </p>
        <p>
            <label asp-for="Price"></label>
            <input asp-for="Price" />
        </p>
        <p>
            <button type="submit" class="btn btn-secondary">Update</button>
        </p>
    </fieldset>
    <h6 style="color:red">@Html.Raw(@ViewBag.Message)</h6>
</form>

Index.cshtml

@{

    ViewBag.Title = "Product";
}
@model List<Product>


<div style="justify-content: space-between; display: flex;">
    <a class="btn btn-success" asp-controller="Products" asp-action="Create">CREATE <i class="fa-solid fa-plus"></i></a>
    <a class="btn btn-danger" asp-controller="" asp-action="">LOG OUT</a>
</div>

<table class="table table-striped pushDown">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Price</th>
            <th>Action</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.Id</td>
                <td>@item.Name</td>
                <td>@item.Price</td>
                <td>
                    <a class="btn btn-primary" asp-controller="Products" asp-action="Edit" asp-route-id="@item.Id">EDIT</a>
                    <a class="btn btn-danger" asp-controller="Products" asp-action="Delete"
                    asp-route-id="@item.Id">DELETE</a>
                </td>
            </tr>
        }
    </tbody>
</table>

To Start

backend

Prerequisites

  1. .NET 6.0

  2. SQL-Server

  3. SSMS

To Start

  1. For Database connection

    Build the solution

    dotnet ef database update

    Expected output

    Build started...
    Build succeeded.
    Done.
    
  2. Use postman or thunderclient further

  3. POST method

    https://localhost:5001/api/authenticate

    There in basic auth use these credentials

    UserName: admin@gmail.com
    Password: Passcode1
    Token would be generated
    Screenshots
    Response
  4. GET method

    https://localhost:5001/api/products

    There in Bearer Token use the token generated

    Screenshots
    Response

frontend

Run it using either of the command

dotnet run
dotnet watch run

Screenshots

  1. Login image

  2. Index image

  3. Create image

  4. Edit image