Current Path : /www/sites/www.coderblog.in/index/
Url:

NameSizeOptions
App_DataDIRnone
backupDIRnone
cgi-binDIRnone
cssDIRnone
imgDIRnone
metaDIRnone
wp-adminDIRnone
wp-contentDIRnone
wp-includesDIRnone
.htaccess3.35 KBDEL
.htaccess.bk1.84 KBDEL
404.html0.13 KBDEL
ads.txt1.07 KBDEL
favicon.ico2.19 KBDEL
index.php0.40 KBDEL
license.txt19.44 KBDEL
php.ini0.58 KBDEL
readme.html7.25 KBDEL
service.php0.00 KBDEL
web.config2.87 KBDEL
wp-activate.php7.21 KBDEL
wp-blog-header.php1.21 KBDEL
wp-comments-post.php2.27 KBDEL
wp-config-sample.php3.26 KBDEL
wp-config.php2.98 KBDEL
wp-cron.php5.49 KBDEL
wp-links-opml.php2.44 KBDEL
wp-load.php3.84 KBDEL
wp-login.php50.21 KBDEL
wp-mail.php8.52 KBDEL
wp-settings.php29.38 KBDEL
wp-signup.php33.71 KBDEL
wp-trackback.php4.98 KBDEL
xmlrpc.php3.13 KBDEL
jwt – Coder Blog https://www.coderblog.in Join the coding revolution! Learn, share, and grow together! Fri, 15 Sep 2023 07:21:19 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 How to support the JWT in Swagger UI https://www.coderblog.in/2023/09/how-to-support-the-jwt-in-swagger-ui/ https://www.coderblog.in/2023/09/how-to-support-the-jwt-in-swagger-ui/#comments Fri, 15 Sep 2023 07:21:19 +0000 https://www.coderblog.in/?p=1097 1. Introduction Swagger is an open specification for describing and documenting RESTful APIs, it is a standard specification

<p>The post How to support the JWT in Swagger UI first appeared on Coder Blog.</p>

]]>
1. Introduction

Swagger is an open specification for describing and documenting RESTful APIs, it is a standard specification and set of tools for defining, producing, consuming, and visualizing RESTful web services. It makes it easy to design, build, document, and consume APIs efficiently.

But, if we are using the JWT in the API (find more in my previous article), you will find that can’t get data from the API in the Swagger UI, because we also need to pass the JWT to the API to get data, but it seems there is no way to do that, right?

Okay, in this article, I will show you how to do that!

2. Setup the Swagger

We can setup the Swagger in the Program.cs with services:

builder.Services.AddSwaggerGen(options =>
{
    //...
}

So, if we want to support JWT in the UI, just need to add the below codes

builder.Services.AddSwaggerGen(options =>
{
     // add JWT Authentication
    var securityScheme = new OpenApiSecurityScheme
    {
        Name = "JWT Authentication",
        Description = "Enter JWT Bearer token **_only_**",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer", // must be lower case
        BearerFormat = "JWT",
        Reference = new OpenApiReference
        {
            Id = JwtBearerDefaults.AuthenticationScheme,
            Type = ReferenceType.SecurityScheme
        }
    };
    options.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {securityScheme, new string[] { }}
    });
});

By the way, you can also change the default Swagger Doc description as below

options.SwaggerDoc("v1", new OpenApiInfo
{
    Version = "v1",
    Title = "MyDemo API",
    Description = "My Demo API by Winson from CoderBlog.in",
    TermsOfService = new Uri("https://www.coderblog.in"),
    Contact = new OpenApiContact
    {
        Name = "Contact",
        Url = new Uri("https://www.coderblog.in")
    },
    License = new OpenApiLicense
    {
        Name = "Example License",
        Url = new Uri("https://example.com/license")
    }
});

3. Find the JWT and use it

After that, restart the website, you will find there is an Authorize button in the Swagger UI.

Figure 1

After clicking this button, it will pop up to let you input the JWT value

Figure 2

Maybe you will ask how can I find the JWT token? All right, you can login to the website in frontend (I am still using this demo site), after login in Chrome, you can find the JWT in the Application tab, and find the local storage

Figure 3

And then input the JWT in Swagger, and you will find that will be a login status.

Figure 4

Also, you can find the lock is changed.

Figure 5

Now, you can try and access your API as well! 🙂

And if you change the Swagger Doc, you will also can find that the Swagger Doc has been changed

Figure 6

4. Conclusion

Swagger is very helpful for testing the API and finding the bugs, but if we use the JWT token then need to do the above settings to allow the Swagger to support it, this can save much of our time for the API testing!~

Loading

<p>The post How to support the JWT in Swagger UI first appeared on Coder Blog.</p>

]]>
https://www.coderblog.in/2023/09/how-to-support-the-jwt-in-swagger-ui/feed/ 9
How to Implement JWT in Core API and Angular — Part 2 https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-2/ https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-2/#comments Fri, 25 Aug 2023 01:02:40 +0000 https://www.coderblog.in/?p=1048 This is post 2 of 2 in the series “How to Implement JWT” In this series, I will

<p>The post How to Implement JWT in Core API and Angular — Part 2 first appeared on Coder Blog.</p>

]]>
  1. How to Implement JWT in Core API and Angular – Part 1
  2. How to Implement JWT in Core API and Angular — Part 2

1. Introduction

We have introduced how to generate the JWT on the server side in previous article, so we will continue to introduce how to handle the JWT in client-side with Angular in this article.

For demonstration, we need to create a simple login page to call the login API, and create another simple page for checking the login token whether is valid, OK, let’s do it!

2. Create the Models

I will base it on the previous demo project for describing. To communicate with the API, we need to create the corresponding models to map the result, so we create a login-request to pass the login data

//MyDemo.Client\src\app\models\login-request.ts

export interface LoginRequest {
  username: string;
  password: string;
}

and create a token model

//MyDemo.Client\src\app\models\token.ts

export interface Token {
  [prop: string]: any;

  //the Jwt token return from API after login successfully
  access_token: string;
  //the current user id
  user_id?: string;
  //should be just handle the 'Bearer' type in this sample
  token_type?: string;
  //How long will be the token expired(e.g. after 30 mins). This is a timestamp format
  expires_in?: number;
  //the actually expire time, so should be the expires_in + current time, e.g. 
  //if expires_in = 30 mins, then exp would be current time + 30 mins
  exp?: number;
}

3. Create the Services

There are 3 services we need to handle:

3.1. Handle Token

First, we need to create a jwt-token to handle the token logic, put these logics into a core folder

//MyDemo.Client\src\app\core\jwt-token.ts

import { Token } from "../models/token";
import { capitalize, currentTimestamp } from "./util";

export class JwtToken {
  constructor(protected attributes: Token) {}

  get access_token(): string {
    return this.attributes.access_token;
  }

  get user_id(): string {
    return this.attributes.user_id ?? '';
  }

  get token_type(): string {
    return this.attributes.token_type ?? 'bearer';
  }

  get exp(): number | void {
    return this.attributes.exp;
  }

  valid(): boolean {
    return this.hasAccessToken() && !this.isExpired();
  }

  getBearerToken(): string {
    return this.access_token
      ? [capitalize(this.token_type), this.access_token].join(' ').trim()
      : '';
  }

  private hasAccessToken(): boolean {
    return !!this.access_token;
  }

  /**
  Check the expired time
  Unit: seconds
  */
  private isExpired(): boolean {
    return this.exp !== undefined && this.exp - currentTimestamp() <= 0;
  }

}

create the util for the common helper methods

//MyDemo.Client\src\app\core\util.ts

/**
 * Capitalize first letter
 * @param text the text wants to be capitalized
 * @returns
 */
export function capitalize(text: string): string {
  return text.substring(0, 1).toUpperCase() + text.substring(1, text.length).toLowerCase();
}

/**
 * Get the current timestamp
 * @returns
 */
export function currentTimestamp(): number {
  return Math.ceil(new Date().getTime() / 1000);
}

/**
 * Filter the Non null object to make sure the object is valid
 * @param obj filter object
 * @returns
 */
export function filterObject<T extends Record<string, unknown>>(obj: T) {
  return Object.fromEntries(
    Object.entries(obj).filter(([, value]) => value !== undefined && value !== null)
  );
}

because we need to save the token into local storage, so create a simple local storage service

//MyDemo.Client\src\app\services\local-storage.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class LocalStorageService {
  get(key: string) {
    return JSON.parse(localStorage.getItem(key) || '{}') || {};
  }

  set(key: string, value: any): boolean {
    localStorage.setItem(key, JSON.stringify(value));

    return true;
  }

  has(key: string): boolean {
    return !!localStorage.getItem(key);
  }

  remove(key: string) {
    localStorage.removeItem(key);
  }

  clear() {
    localStorage.clear();
  }
}

in the end, create a token service to put these together

//MyDemo.Client\src\app\services\token.service.ts

import { Injectable, OnDestroy } from '@angular/core';
import { Token } from '../models/token';
import { LocalStorageService } from './local-storage.service';
import { JwtToken } from '../core/jwt-token';
import { currentTimestamp, filterObject } from '../core/util';

@Injectable({
  providedIn: 'root',
})
export class TokenService implements OnDestroy {
  private key = 'MyDemo-token';

  private _token?: JwtToken;

  constructor(private store: LocalStorageService) {}

  private get token(): JwtToken | undefined {
    if (!this._token) {
      this._token = new JwtToken(this.store.get(this.key));
    }

    return this._token;
  }

  set(token?: Token): TokenService {
    this.save(token);

    return this;
  }

  clear(): void {
    this.save();
  }

  valid(): boolean {
    return this.token?.valid() ?? false;
  }

  getUserid(): string {
    return this.token?.user_id ?? '';
  }

  getBearerToken(): string {
    return this.token?.getBearerToken() ?? '';
  }

  ngOnDestroy(): void {
  }

  /**
   * Save the token to local storage
   * @param token token model
   */
  private save(token?: Token): void {

    this._token = undefined;

    if (!token) {
      this.store.remove(this.key);
    } else {
      const value = Object.assign({ access_token: '', token_type: 'Bearer' }, token, {
        exp: token.expires_in ? currentTimestamp() + token.expires_in : null,
      });
      this.store.set(this.key, filterObject(value));
    }
  }
}

3.2. Authentication Service

We will call the API to login the system and get the Jwt token, so we need an auth service to handle the login and logout logic

import { Injectable } from '@angular/core';
import { map, tap } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { config } from 'src/assets/config';
import { Token } from '../models/token';
import { TokenService } from './token.service';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root',
})
export class AuthService {

  constructor(
    private tokenService: TokenService, private router: Router,
    protected http: HttpClient) {}

    /**
     * Call the API to login
     * @param username user name
     * @param password password
     * @returns Jwt token if login successfully
     */
    login(username: string, password: string) {

      var url = config.apiUrl + "/auth/login";
      //call the API to get token after login successfully
      return this.http.post<Token>(url, { username, password }).pipe(
        tap(token => {
          console.log('auth service logined ', token);
          //save the token into local storage
          this.tokenService.set(token);
        }),
        map(() => {
          console.log('auth service logined and map ', this.check());
          //check the token whether is valid
          return this.check();
        })
      );
    }

    /**
     * Clear the token after logout
     */
    logout(){
      this.tokenService.clear();
      this.router.navigateByUrl('/login');
    }

    check() {
      return this.tokenService.valid();
    }
}

4. Create the Login page

After creating the essential models and services, we can create the login page now. Run the below command to create a login page

ng g c Login --skip-tests

Cause we are just for demonstration, so only need to create a simple login layout :

<!-- MyDemo.Client\src\app\login\login.component.html -->

<p>Login</p>
<div class="row">
  <form class="form-field-full" [formGroup]="loginForm">
  <div class="col-sm-12">
      <mat-form-field class="col-sm-3">
        <mat-label>User Name: </mat-label>
        <input matInput formControlName="username" placeholder="User Name">
      </mat-form-field>
  </div>
  <div  class="col-sm-12">
      <mat-form-field class="col-sm-3">
        <mat-label>Password: </mat-label>
        <input matInput formControlName="password" type="password" placeholder="Password">
      </mat-form-field>

  </div>
  <div  class="col-sm-12">
    <button class="m-r-8 bg-green-700 text-light" mat-raised-button  (click)="login()">Login</button>
  </div>
  <div class="col-sm-12">
    <span style="color: red;" *ngIf="errorMsg != ''">{{ errorMsg }}</span>
  </div>
</form>
</div>

we can use the FormBuilder to get the input values and pass them to the login function

//MyDemo.Client\src\app\login\login.component.ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { FormBuilder } from '@angular/forms';
import { filter } from 'rxjs/operators';
import { HttpErrorResponse } from '@angular/common/http';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent {

  constructor(private fb: FormBuilder, 
          private router: Router, 
          private auth: AuthService) {
  }

  public errorMsg: string = '';

  //init the loginForm 
  loginForm = this.fb.nonNullable.group({
    username: '',
    password: '',
  });

  get username() {
    return this.loginForm.get('username')!;
  }

  get password() {
    return this.loginForm.get('password')!;
  }

  login() {
    this.auth
      .login(this.username.value, this.password.value)
      .pipe(filter(authenticated => authenticated))
      .subscribe(
        () => {
          //redirect to user management page if login successfully
          this.router.navigateByUrl('/user-management');
        },
        (errorRes: HttpErrorResponse) => {
          //otherwise then update the error message in the page
          if(errorRes.status == 401){
            this.errorMsg = 'User name or password is not valid!';
          }
            console.log('Error', errorRes);
        }
      );
  }
}

Ok, we can take a look at the result :

1) Input the user name and password and click login

2) It will return the token (can find it in local storage ) and redirect to the user management page

Seems great, right? 🙂

But please hold on, we still have some problems. You will find that if you access the user management page directly and it also can be successful, that means the page didn’t check the login token, that does not make sense.

5. Add the guard for the user pages

We can solve the above issue with guard in Angular. The guard in Angular refers to route guards, which are interfaces that allow you to control navigation and access to routes in your Angular application. route guards allow you to check if a user can activate or deactivate a route, by implementing CanActivate or CanDeactivate interfaces. You can find more details here.

Create the route guards as below:

//MyDemo.Client\src\app\core\auth.guard.ts

import { Injectable } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  CanActivate,
  CanActivateChild,
  RoutesRecognized,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { filter, pairwise } from 'rxjs/operators';
import { AuthService } from '../services/auth.service';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanActivateChild {

  previousUrl!: string;
  currentUrl!: string;

  constructor(private auth: AuthService, private router: Router) {
    this.router.events
      .pipe(filter((evt: any) => evt instanceof RoutesRecognized), pairwise())
      .subscribe((events: RoutesRecognized[]) => {
        this.previousUrl = events[0].urlAfterRedirects;
        this.currentUrl = events[1].urlAfterRedirects;
      });
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.authenticate();
  }

  canActivateChild(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean | UrlTree {
    return this.authenticate();
  }

  private authenticate(): boolean | UrlTree {
    //check whether is login successfully
    if (this.auth.check()) {
      return true;
    }
    else{
      this.router.navigateByUrl('/login');
    }
    return false;
  }
}

and use it in app routing, add the canActivate in the routes

//MyDemo.Client\src\app\app-routing.module.ts

const routes: Routes = [
  { path: 'user-management', component: UserManagementComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
];

after that, logout of the page and try to access the user management page directly, you will find that will be auto redirected to the login page!

6. Create the Interceptor

We are almost done, but still, there is an issue that needs to be solved! Even if we can login successfully and redirect to the user management page, we still can’t get the user data, because there is an authorized checking with the user controller API, so we need to pass the token to the API when we get the user data.

We can append the HTTP header with Authorization when calling the get user API /api/users, but we also need to do that for every API, so this is not a good approach!

The best way that we can use the interceptor.

Interceptors in Angular are services that allow you to intercept and transform HTTP requests and responses between your application and the server. Request interceptors can modify headers, add authentication tokens, log requests, etc.

Create the token-interceptor as below

//MyDemo.Client\src\app\core\token-interceptor.ts

import { Injectable } from '@angular/core';
import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { TokenService } from '../services/token.service';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor(
    private tokenService: TokenService,
    private router: Router
  ) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    const handler = () => {
      //check the url if login then just redirect to user management page after login     
      if (this.router.url.includes('/login')) {
        this.router.navigateByUrl('/user-management');
      }
    };

    if (this.tokenService.valid()) {
      //if the token is valid, then append to the http header for each request
      return next
        .handle(
          request.clone({            
            headers: request.headers.append('Authorization', this.tokenService.getBearerToken()),
            withCredentials: true,
          })
        )
        .pipe(
          catchError((error: HttpErrorResponse) => {
            //error handler
            if (error.status === 401) {
              this.tokenService.clear();
            }
            return throwError(error);
          }),
          tap(() =>{
            handler();})
        );
    }

    return next.handle(request).pipe(tap(() =>{
        handler();
      }));
  }
}

add a provider in app.module

@NgModule({
  ...
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },
  ],
  ...
})

after that, the TokenInterceptor will auto append the token in http header for each request.

login to the page again, you will see all of the user data as well!

7. Conclusion

Jwt is a better way to handle the API authorization, after this article, we learned how to handle the Jwt token in Angular, the flow should be as below:

1) Call API login function and get the token after successfully
2) Save the token in local storage
3) Add the checking for each user’s pages
4) Pass the token to each API request to get data

In the end, don’t forget there are two main points that create the router guard for checking login token and an interceptor for sending token to API.

Loading

<p>The post How to Implement JWT in Core API and Angular — Part 2 first appeared on Coder Blog.</p>

]]>
https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-2/feed/ 7
How to Implement JWT in Core API and Angular – Part 1 https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-1/ https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-1/#comments Mon, 21 Aug 2023 08:21:03 +0000 https://www.coderblog.in/?p=1015 This is post 1 of 2 in the series “How to Implement JWT” In this series, I will

<p>The post How to Implement JWT in Core API and Angular – Part 1 first appeared on Coder Blog.</p>

]]>
  1. How to Implement JWT in Core API and Angular – Part 1
  2. How to Implement JWT in Core API and Angular — Part 2

1. Introduction

JWT means JSON Web Tokens, it usually uses for API authorization with the client. JWT is an open standard that defines a way to transmit information between two parties securely as a JSON object in a compact and verifiable way. It is great for securing REST APIs and authorization. There are some common use cases of JWT include:

1) Authorization – Once the user is logged in, each subsequent request will include the JWT to allow access to routes, services, and resources.

2) Information Exchange – JWT is a good way of securely transmitting information between parties.

3) User information storage – JWT can store user details, preferences, etc in a web/mobile application.

The benefits of using JWT include compact size, url-safe, ability to be encrypted, decentralized, suitable for mobile apps, and more.

And in this post, I will show you how to use JWT for .Net Core API and Angular.

2. The flow for using JWT

Let’s take a look at the flow for how’s the JWT working:

1) Client calls the API for a login request
2) Server(API) side generates JWT after login success
3) Pass the JWT to client-side
4) Client-side needs to save the JWT
5) Client passes the JWT to the API for each request
6) Server-side needs to verify the JWT from the client’s request, if successful then return the data otherwise return auth failed message.

3. Generate the JWT

We can create a JWT service to help to do that! We will use JwtSecurityToken to generate the JWT, this method under System.IdentityModel.Tokens.Jwt namespace, let’s take a look at the signature for this method. There are 4 overwrite methods for this, but we will use the below

public JwtSecurityToken(string issuer = null, string audience = null, 
                IEnumerable<Claim> claims = null, DateTime? notBefore = null, DateTime? 
                expires = null, SigningCredentials signingCredentials = null);

suppose we can let the parameters be null, but for safer, we will use all of them. We can put these parameters into appsettings.json so that can be control

"JwtSettings": {
    "SecurityKey": "MyVeryOwnSecurityKey",
    "Issuer": "MyVeryOwnIssuer",
    "Audience": "https://localhost:4810",
    "ExpirationTimeInMinutes": 1440
  },

and use them to create the token

var jwtOptions = new JwtSecurityToken(
             issuer: _configuration["JwtSettings:Issuer"],
             audience: _configuration["JwtSettings:Audience"],
             claims: GetClaims(user),
             expires: DateTime.Now.AddMinutes(Convert.ToDouble(
                     _configuration["JwtSettings:ExpirationTimeInMinutes"])),
             signingCredentials: GetSigningCredentials());

the complete codes for the JwtService as below

using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using MyDemo.Core.Data.Entity;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace MyDemo.Core.Services;

public class JwtService
{
    private readonly IConfiguration _configuration;
    public JwtService(IConfiguration configuration)
    {
        //inject the configuration for getting the setting values
        _configuration = configuration;
    }
    public JwtSecurityToken GetToken(User user)
    {
        //create the Jwt token from setting values
        var jwtOptions = new JwtSecurityToken(
                        issuer: _configuration["JwtSettings:Issuer"],
                        audience: _configuration["JwtSettings:Audience"],
                        claims: GetClaims(user),
                        expires: DateTime.Now.AddMinutes(Convert.ToDouble(
                                _configuration["JwtSettings:ExpirationTimeInMinutes"])),
                        signingCredentials: GetSigningCredentials());
        return jwtOptions;
    }
    //generate signing credentials
    private SigningCredentials GetSigningCredentials()
    {
        var key = Encoding.UTF8.GetBytes(_configuration["JwtSettings:SecurityKey"]);
        var secret = new SymmetricSecurityKey(key);
        return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
    }
    //create the claim base current user name and email
    private List<Claim> GetClaims(User user)
    {
        var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Email) };
        return claims;
    }
}

4. Create the Login function

We need to create an API login function to return the JWT to the client.

4.1 Create the DTO

Before we start, we need to receive the login request object and a result object for return to the client, so we need to create two DTOs for the login function. In this way, I will simply introduce what’s DTO.

DTO stands for Data Transfer Object. It is a design pattern used to transfer data between different layers of an application, such as between the UI layer and the business logic layer. The main purpose of a DTO is to transfer data, so they don’t contain any behavior except for storage, retrieval, serialization, and deserialization of data.

We can create a DTO folder under the Data folder and create the LoginRequest.cs in this folder

//MyDemo.Core/Data/DTO/LoginRequest.cs

namespace MyDemo.Core.Data.DTO;

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; } 
}

and the result object for returning the token

//MyDemo.Core/Data/DTO/LoginToken.cs

namespace MyDemo.Core.Data.DTO;

public class LoginToken
{
    /// <summary>
    /// The JWT token if the login attempt is successful, or NULL if not
    /// </summary>
    public string? access_token { get; set; }
    public string? user_id { get; set; }
    public string? token_type { get; set; }
    /// <summary>
    /// expires time in seconds
    /// </summary>
    /// <value></value>
    public int? expires_in { get; set; }
}

4.2. Create the Auth API

Create the AuthController to handle the login function, and we need to inject the below instance first

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IUserRepository _userRepository;
    private readonly JwtService _jwtService;
    private readonly IConfiguration _configuration;
    private readonly ILogger<AuthController> _logger;

    public AuthController(IUserRepository userRepository,
                        JwtService jwtService,
                        IConfiguration configuration,
                        ILogger<AuthController> logger)
    {
        _userRepository = userRepository;
        _jwtService = jwtService;
        _configuration = configuration;
        _logger = logger;
    }
}

create the login API to receive a LoginRequest

[HttpPost("Login")]
public async Task<IActionResult> Login(LoginRequest loginRequest)
{
    //todo...
}

check the user name and password for login, if successful then generate the token, otherwise, return the null data.

var user = await _userRepository.GetItemWithConditionAsync(
    u => u.Name == loginRequest.Username && u.Password == loginRequest.Password);
if (user == null)
{
    return Unauthorized(new LoginToken()
    {
        access_token = null,
        user_id = null,
        expires_in = 0,
        token_type = "Bearer"
    });
}
//generate a token by user information and appsettings values
var secToken = _jwtService.GetToken(user);
//serializes the token into a JWT format
var jwt = new JwtSecurityTokenHandler().WriteToken(secToken);
//get the expiration times and pass them to the client
var expires_sec = Convert.ToInt32(_configuration["JwtSettings:ExpirationTimeInMinutes"]) * 60;
return Ok(new LoginToken()
{
    access_token = jwt,
    user_id = user.Id.ToString(),
    expires_in = expires_sec,
    token_type = "Bearer"
});

by the way, this is only for a demo, so I didn’t encrypt the password, you should encrypt it in a real project.

and we should use try...catch to handle exceptions in a complete function

[HttpPost("Login")]
public async Task<IActionResult> Login(LoginRequest loginRequest)
{
    try
    {
        var user = await _userRepository.GetItemWithConditionAsync(
            u => u.Name == loginRequest.Username && u.Password == loginRequest.Password);
        if (user == null)
        {
            return Unauthorized(new LoginToken()
            {
                access_token = null,
                user_id = null,
                expires_in = 0,
                token_type = "Bearer"
            });
        }
        //generate a token by user information and appsettings values
        var secToken = _jwtService.GetToken(user);
        //serializes the token into a JWT format
        var jwt = new JwtSecurityTokenHandler().WriteToken(secToken);
        //get the expiration times and pass them to the client
        var expires_sec = Convert.ToInt32(_configuration["JwtSettings:ExpirationTimeInMinutes"]) * 60;
        return Ok(new LoginToken()
        {
            access_token = jwt,
            user_id = user.Id.ToString(),
            expires_in = expires_sec,
            token_type = "Bearer"
        });
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Login Error");
        return StatusCode(500);
    }
}

5. Setup Program.cs

In the end, we also need to add the service to program.cs file. Before that, we need to install the below package to API project from Nuget first

Microsoft.AspNetCore.Authentication.JwtBearer

and add the below codes

// Add Authentication services & middlewares
builder.Services.AddAuthentication(opt =>
{
    opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        RequireExpirationTime = true,
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["JwtSettings:Issuer"],
        ValidAudience = builder.Configuration["JwtSettings:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.
                GetBytes(builder.Configuration["JwtSettings:SecurityKey"]))
    };
});

builder.Services.AddScoped<JwtService>();

Ok, let’s take a look at the result in the swagger UI

Figure

Great! We got the token after login successfully!

6. Authorize the User Controller

We have created the login token but we still need to add the authorization to the user controller, otherwise, the token will be useless, just adding the attribute to the user controller will be ok

[Authorize()]
public class UserController : ControllerBase
{
    //...
}

7. Conclusion

We have learned how to generate and handle the Jwt on the server side (API), the main port that uses the JwtSecurityToken to generate a token and serialize it into a JWT format and return it to the client. Because that’s more complex for implementing on the client side, so I split to part 2 to describe how to handle it on the client side in the next article! 🙂

Loading

<p>The post How to Implement JWT in Core API and Angular – Part 1 first appeared on Coder Blog.</p>

]]>
https://www.coderblog.in/2023/08/how-to-implement-jwt-in-core-api-and-angular-part-1/feed/ 15