Thursday, December 21, 2023

Two Factor Authentication using .Net Core

Install Package

dotnet add package GoogleAuthenticator --version 3.1.1


Model Changes

public bool IsAuthenticatorReset { get; set; }

public string UniqueAuthenticatorKey { get; set; }

Method for updating AuthenticationKey

 public async Task<string> UpdateUniqueAuthenticatorKey(AppUser user, string UniqueAuthenticatorKey)

        {

            //var user = (await _appUserRepository.List(x => x.Email == email)).FirstOrDefault();

            if (user != null)

            {

                user.UniqueAuthenticatorKey = UniqueAuthenticatorKey;

                await _userManager.UpdateAsync(user);

                return "success";


            }

            return "error";

        }


Steps ActionMethod

public async Task<IActionResult> LoginWithAuthenticatorStepOne(string email, string userName, string returnUrl)

        {

            try

            {

                var user = await _userManager.FindByEmailAsync(email);

                string googleAuthKey = _configuration["ApplicationSettings:GoogleAuthKey"].ToString();

                string UserUniqueKey = (user.Id.ToString() + googleAuthKey + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString());

                await _appUserService.UpdateUniqueAuthenticatorKey(user, UserUniqueKey);

                //Two Factor Authentication Setup

                TwoFactorAuthenticator TwoFacAuth = new TwoFactorAuthenticator();

                var setupInfo = TwoFacAuth.GenerateSetupCode("CDS", userName, ConvertSecretToBytes(UserUniqueKey, false), 300);

                ViewBag.BarcodeImageUrl = setupInfo.QrCodeSetupImageUrl;

                HttpContext.Session.Remove("QrCodeSetupImageUrl");

                HttpContext.Session.SetString("QrCodeSetupImageUrl", setupInfo.QrCodeSetupImageUrl);

                ViewBag.SetupCode = setupInfo.ManualEntryKey;

                return View(new LoginModel { Username = userName });

            }

            catch (Exception ex)

            {

                ModelState.AddModelError("Error", ex.Message);

                return View(new LoginModel { Username = userName });

            }

        }

public async Task<IActionResult> LoginWithAuthenticatorNext(LoginModel model, string returnUrl = null)

        {

            var user = await _userManager.FindByNameAsync(model.Username);

            if (user != null && user.IsActive)

            {

                return RedirectToAction("LoginWithAuthenticatorStepTwo", new { user.Email, user.UserName, returnUrl });

            }

            else

            {

                ModelState.AddModelError("Error", "Invalid or Inactive User");

                return View("LoginWithAuthenticatorNext", model);

            }

        }


        public async Task<IActionResult> LoginWithAuthenticatorStepTwo(string email, string userName, string returnUrl)

        {

            try

            {

                var user = await _userManager.FindByEmailAsync(email);

                if (user != null && user.IsActive)

                {

                    return View(new LoginModel { Username = userName });

                }

                else

                {

                    ModelState.AddModelError("Error", "Invalid or Inactive User");

                    return View("LoginWithAuthenticatorStepTwo", new { user.Email, user.UserName, returnUrl });

                }

            }

            catch (Exception ex)

            {

                ModelState.AddModelError("Error", ex.Message);

                return View(new LoginModel { Username = userName });

            }

        }

Method for checking Authenticator

        public async Task<IActionResult> TwoFactorAuthenticate(LoginModel model, string returnUrl = null)

        {

            ViewData["returnUrl"] = returnUrl;

            var version = await _settingService.GetVersionSetting();

            ViewData["downloadURL"] = version.Where(x => x.Name == "DesktopAppURL").FirstOrDefault()?.Key;


            var user = await _userManager.FindByNameAsync(model.Username);

            if (user != null && user.IsActive)

            {

                var role = await _userManager.GetRolesAsync(user);

                TwoFactorAuthenticator TwoFacAuth = new TwoFactorAuthenticator();

                string userUniqueKey = user.UniqueAuthenticatorKey;

                bool isLoggedIn = Convert.ToBoolean(HttpContext.Session.GetString("isLoggedIn"));

                bool isValid = TwoFacAuth.ValidateTwoFactorPIN(userUniqueKey, model.OTP, false);

                if (isValid && isLoggedIn)

                {

                    HttpContext.Session.SetString("isLoggedIn", "false");

                    await _appUserService.ResetAuthenticator(user.Id, true);

                    await _signInManager.SignOutAsync();

                    await _signInManager.SignInAsync(user, true);

                    var token = _tokenCreationService.CreateJWTtokenForWeb(user, role.FirstOrDefault());

                    ViewData["Token"] = token.Token;

                    ViewData["RefreshToken"] = token.Refresh_Token;

                    UserRefreshToken obj = new UserRefreshToken

                    {

                        RefreshToken = token.Refresh_Token,

                        UserName = user.UserName,

                        IsActive = true,

                        CreatedAt = DateTime.Now,

                    };


                    _jWTRepository.AddUserRefreshTokens(obj);

                    _jWTRepository.SaveCommit();

                    TempData["LoginName"] = user.FirstName + " " + user.LastName;

                    TempData.Keep("LoginName");

                    return Redirect("/Dashboard");

                }

                else

                {

                    ViewBag.BarcodeImageUrl = HttpContext.Session.GetString("QrCodeSetupImageUrl");

                    ModelState.AddModelError("Error", "Invalid Code");

                    return View("LoginWithAuthenticatorStepTwo", model);

                }

            }

            ViewBag.BarcodeImageUrl = HttpContext.Session.GetString("QrCodeSetupImageUrl");

            ModelState.AddModelError("Error", "Invalid or Inactive User");

            return View("LoginWithAuthenticatorStepTwo", model);

        }


 private static byte[] ConvertSecretToBytes(string secret, bool secretIsBase32) =>

           secretIsBase32 ? Base32Encoding.ToBytes(secret) : Encoding.UTF8.GetBytes(secret);



Reset Authenticator

public async Task<bool> ResetAuthenticator(int userId, bool isReset)

        {

            try

            {

                var user = await _appUserRepository.GetById(userId);

                user.IsAuthenticatorReset = isReset;

                await _appUserRepository.Update(user);

                return true;

            }

            catch

            {

                return false;

            }

        }



Note: so in this authentication, what we are achieving is, let's gather throw points:

i- Authentication setup code and qr code only setup once.

ii- if user deleted the app then he needs to again contact to the admin to reissue the qr code mean a new app.

iii- only one time QR code will show.



.net core migrations

Generate Script 



Package Manager Console


Script-Migration -From 20231221063632_UniqueAuthenticatorKey -To 20231221063632_UniqueAuthenticatorKey


.net CLI


dotnet ef migrations script -i -o "C:\Path\To\Your\Script.sql" -s YourStartupProject -p YourDataProject -from 20231221063632_UniqueAuthenticatorKey -to 20231221063632_UniqueAuthenticatorKey


===============================

No migrations configuration type was found in the assembly 'CompleteDiscoverySource.Website'. (In Visual Studio you can use the Enable-Migrations command from Package Manager Console to add a migrations configuration)


EntityFrameworkCore\Add-Migration "migrationName"

===============================



Monday, July 17, 2023

JWT Token

 1. Insall packages

1. System.IdentityModel.Tokens.jwt 6+

2. Microsoft.IdentityModl.TOkens 6+

3. Micorsoft.AspNetCore.Authentication.JwtBearere 3.12

2. Update in Startup.cs File


3. Create the JWTService to generate Tokens in String Format.


4. Sent it whenever login is Successfull.


5. Receive this token in FrontEnd and stroe it in Browser's local storage.

for Angular

6. npm install @auth0/angular-jwt


Git Hub Links:
.NET Core: Fullstack.API  

Angular: Fullstack.UI



Friday, July 7, 2023

issues while working on .net core angular crud

 ===================================================================

Notes

===================================================================





===================================================================

VS Code Extension

these extension are installed when I was working on this project.

Angular Language Service

===================================================================





===================================================================

Issues faced on Angular Side

------------------------------------------------------------------

1- Angular CLI Version

I first install angular cli but due to old node js version it was not installing correctly so I did update the version of node js. but after updating the verion angular cli was

giving me another error:

Error: You need to specify a command before moving on. Use '--help' to view the available commands

so I used this technique to fix the issue

100


Uninstall Angular old version & Install latest version (14)


npm uninstall -g @angular/cli 

npm install -g @angular/cli

Use:


ng version | ng v

Instead of:


ng -v | ng --version


------------------------------------------------------------------

2- Now when I'm running my project after creating new angular project by running command (ng new {projectName}), I'm facing issue on running command: ng serve --open or ng server

issue: ng : File C:\Users\TK-LPT-654\AppData\Roaming\npm\ng.ps1 cannot be loaded because running scripts is disabled on this system. For more information, 

see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.


you need to give permission to you CurrentUser as RemoteSigned, for this purpose enter the below command:


Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 


one more thing I want to add, I was making a mistake while running this command. I'm running this command on window cammand prompt and I was getting error:

'Get-ExecutionPolicy' is not recognized as an internal or external command,

operable program or batch file.


so do not try to run on cmd instead use the visual studo code terminal and run this command and then it will work perfectly.


after running the above command

run another command

Get-ExecutionPolicy

result: RemoteSigned


also you can run this command 

Get-ExecutionPolicy -list

Result:

        Scope ExecutionPolicy

        ----- ---------------

MachinePolicy       Undefined

   UserPolicy       Undefined

      Process       Undefined

  CurrentUser    RemoteSigned

 LocalMachine       Undefined

------------------------------------------------------------------


I'm using angular 16 and I need to add baseapiurl in the environment but I noticed there is no such folder exists in the system. so now I came to know that in angular 15 and above versions

environment folder has been removed and now If we will have to add manually by running a command: ng g enviroments

then I was able to add the environment.


------------------------------------------------------------------


===================================================================



===================================================================

Issues faced on .NET 6 Side



------------------------------------------------------------------

when I was showing green lines on the model properties so when I tried to remove it by disabling the nullable from the project then I saw many errors

which were saying many type doesn't exist in the current context so I added manually then again I saw I added wrong namespace then I again went to the project

and saw I made a mistake I had disabled the ImplicitUsings instead of Nullable so be careful while changing Nullable.


------------------------------------------------------------------







===================================================================

rough work:

employee model:

id, name, email, phone, salary, department


===================================================================


Wednesday, September 21, 2022

ASP NET CORE ENTITY FRAMEWORK CODE FIRST APPROACH

******************************************************************************

******************************************************************************

//For Entity Framework

Microsoft.EntityFrameworkCore

Microsoft.EntityFrameworkCore.SqlServer

Microsoft.EntityFrameworkCore.Tools

******************************************************************************

//For Swagger Installation

Install Swashbuckle.AspNetCore.SwaggerUI and Swashbuckle.AspNetCore.SwaggerGen.


Configure Services Method


 services.AddSwaggerGen(c =>

            {

                c.SwaggerDoc("v2", new OpenApiInfo { Title = "My API", Version = "v2" });

            });


Configure Method


 app.UseSwagger();

            app.UseSwaggerUI(c =>

            {

                c.SwaggerEndpoint("/swagger/v2/swagger.json", "My API V1");

            });

******************************************************************************

//For DbContext


public class DataContext: DbContext

    {

        public DataContext(DbContextOptions<DataContext> options): base(options)

        {


        }

        public DbSet<Department> Departments { get; set; }


// Adding Db Context in Configure Services Method in Startup class

services.AddDbContext<DataContext>(options =>

            {

                options.UseSqlServer(Configuration.GetConnectionString("myLocalDb"));

            });


******************************************************************************


// Specific Migration add

Add-Migration -context datacontext(class name in lowercase)


// specific database update

Update-Database -context datacontext


******************************************************************************

adding allowed CORS in Configure Serivces Method in Startup class

services.AddCors(c =>

            {

                c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

            });


using allowed CORS in Configure Method in Startup class



app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());


******************************************************************************



using static file option

in configure method in startup.cs file

app.UseStaticFiles(new StaticFileOptions

            {

                FileProvider = new PhysicalFileProvider(

                    Path.Combine(Directory.GetCurrentDirectory(),"Photos")),

                RequestPath = "/Photos"

            });


******************************************************************************


Adding Entity

public class DepartmentController : ControllerBase

    {

        private DataContext _dataContext;

        public DepartmentController(DataContext dataContext)

        {

            _dataContext = dataContext;

        }

        [HttpPost]

        public ActionResult<Department> AddDepartment(Department department)

        {

            _dataContext.Departments.Add(department);

            _dataContext.SaveChanges();

            return department;

        }

    }


******************************************************************************

connectionString in appsettings.json

{

  "Logging": {

    "LogLevel": {

      "Default": "Information",

      "Microsoft": "Warning",

      "Microsoft.Hosting.Lifetime": "Information"

    }

  },

  "ConnectionStrings": {

    "myLocalDb": "Server=(local)\\SQLEXPRESS;Database= CodeFirstDb;Trusted_Connection = true;MultipleActiveResultSets=True"

  },

  "AllowedHosts": "*"

}


******************************************************************************

******************************************************************************

Thursday, July 16, 2020

setting routes code

const appRoutes: Routes = [
    {
        path: "home",
        component: HomeComponent
    },
    {
        path: "employees",
        component: EmployeeListComponent
    },
    {
        path: "**",
        redirectTo: "/home",
        pathMatch : "full"
    }
];

@NgModule({
    imports: [BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes)],
    declarations: [AppComponent, EmployeeComponent, TutorialComponent, EmployeeListComponent,
        EmployeeTitlePipe, EmployeeCountComponent, SimpleComponent],
    bootstrap: [AppComponent]
})

Setting Route code

const appRoutes: Routes = [
    {
        path: "home",
        component: HomeComponent
    },
    {
        path: "employees",
        component: EmployeeListComponent
    },
    {
        path: "**",
        redirectTo: "/home",
        pathMatch : "full"
    }
];

@NgModule({
    imports: [BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes)],
    declarations: [AppComponent, EmployeeComponent, TutorialComponent, EmployeeListComponent,
        EmployeeTitlePipe, EmployeeCountComponent, SimpleComponent],
    bootstrap: [AppComponent]
})

Two Factor Authentication using .Net Core

Install Package dotnet add package GoogleAuthenticator --version 3.1.1 Model Changes public bool IsAuthenticatorReset { get; set; } public s...