101 Security: Authentication. Server Side. - chempkovsky/CS82ANGULAR GitHub Wiki

Two aspects

Security has two aspects: Authentication and Authorization

Steps required to accomplish the task

Database context

  • There is no special t4 script to generate code for the Security Database context, because we will use the IdentityDbContext implementation of Microsoft.
  • Reminder: We have already added the reference to the Microsoft.AspNetCore.Identity.EntityFrameworkCore package.
  • Create AspNetReg-folder in the PhBkContext.csproj-project
  • Add AspNetRegistrationDbContext-class to AspNetReg-folder of the PhBkContext.csproj-project
  • Modify the file as follows:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace PhBkContext.AspNetReg
{
    public class AspNetRegistrationDbContext : IdentityDbContext<IdentityUser>
    {
        public AspNetRegistrationDbContext(DbContextOptions<AspNetRegistrationDbContext> options) : base(options)
        {
            Database.EnsureCreated();
        }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
        }

    }
}

appsettings json file

  • Add AspNetRegConnection-item in the ConnectionStrings-secion of the appsettings.json- file
  • Add JWT-section to the appsettings.json- file
  "ConnectionStrings": {
    "PhBkConnection": "Data Source=SVR2016SQL2017;Initial Catalog=PhBkDbDef;Persist Security Info=True;User ID=sa;Password=your_password_here",
    "AuthConnection": "Data Source=SVR2016SQL2017;Initial Catalog=PhBkDbAuth;Persist Security Info=True;User ID=sa;Password=your_password_here",
    "AspNetRegConnection": "Data Source=SVR2016SQL2017;Initial Catalog=PhBkAspNet;Persist Security Info=True;User ID=sa;Password=your_password_here"
  },
  "JWT": {
    "ValidAudience": "PhBkAudience",
    "ValidIssuer": "PhBkIssuer",
    "Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr"
  }

Program file of PhBkWebApp app

...
using Microsoft.AspNetCore.Identity;
using PhBkContext.AspNetReg;
...

var builder = WebApplication.CreateBuilder(args);
...
ConfigurationManager configuration = builder.Configuration;
...

#region authentification
builder.Services.AddDbContext<AspNetRegistrationDbContext>(options =>
    options.UseSqlServer(configuration.GetConnectionString("AspNetRegConnection")));
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<AspNetRegistrationDbContext>().AddDefaultTokenProviders();
builder.Services.AddAuthentication(options => {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => {
    options.SaveToken = true;
    options.RequireHttpsMetadata = true;
    options.TokenValidationParameters = new TokenValidationParameters() {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidAudience = configuration["JWT:ValidAudience"],
        ValidIssuer = configuration["JWT:ValidIssuer"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"]))
    };
});
builder.Services.AddHttpContextAccessor();
#endregion

...
var app = builder.Build();
  • In the file Program.cs-file of the PhBkWebApp-project insert the following code below the var app = builder.Build();-line
var app = builder.Build();
...
#region authentification
app.UseAuthentication();
#endregion
app.UseAuthorization();

Account controller Dto

  • We need to define data structures which Account controller sends to clients and receives from the clients
  • Create AspNetReg-folder in the PhBkViews.csproj-project
Run JavaScript Wizard for Dto
  • right click AspNetReg-folder of the PhBkViews.csproj-project
    • select JavaScript Wizard-menu item
Click to show the picture

project structure

First page for Dto
  • click Next-button on the first page
Second page for Dto
  • Select PhbkContext-project and PhbkDbContext-context and click Next-button
Click to show the picture

project structure

Third page for Dto
  • Select ==Context== and click Next-button
Click to show the picture

project structure

Fourth page for Dto
  • Click Batch processing-button
    • Batch Actions-dialog will be shown
Click to show the picture

project structure

Batch Actions Dialog for Dto
  • select 00370-AspNetRegistration.json- batch script and click start
    • four files will be created
  • close dialog and close the Wizard
Click to show the picture

project structure

Account controller

  • Now we need the WebApi controller which implements login, register user, change password
Run JavaScript Wizard
  • right click Controllers-folder of the PhBkControllers.csproj-project
    • select JavaScript Wizard-menu item
Click to show the picture

project structure

First page
  • click Next-button on the first page
Second page
  • Select PhbkContext-project and PhbkDbContext-context and click Next-button
Click to show the picture

project structure

Third page
  • Select ==Context== and click Next-button
Click to show the picture

project structure

Fourth page
  • Click Batch processing-button
Click to show the picture

project structure

Batch Actions Dialog
  • select 00380-AspNetAccountController.json- batch script and click start
    • four files will be created
  • close dialog and close the Wizard
Click to show the picture

project structure

Modify controller
        private async Task CreateAdminAndGuest()
        {
            IdentityUser adminUser = await _userManager.FindByNameAsync("[email protected]");
            if (adminUser != null) return;
            adminUser = new() {
                Email = "[email protected]",
                SecurityStamp = Guid.NewGuid().ToString(),
                UserName = "[email protected]"
            };

            IdentityResult result = await _userManager.CreateAsync(adminUser, "[email protected]");
            if (!result.Succeeded) return;

            if (!await _roleManager.RoleExistsAsync("AdminRole")) await _roleManager.CreateAsync(new IdentityRole("AdminRole"));
            if (!await _roleManager.RoleExistsAsync("GuestRole")) await _roleManager.CreateAsync(new IdentityRole("GuestRole"));


            if (await _roleManager.RoleExistsAsync("AdminRole"))
            {
                await _userManager.AddToRoleAsync(adminUser, "AdminRole");
            }

            IdentityUser guestUser = await _userManager.FindByNameAsync("[email protected]");
            if (guestUser != null) return;
            guestUser = new() {
                Email = "[email protected]",
                SecurityStamp = Guid.NewGuid().ToString(),
                UserName = "[email protected]"
            };
            result = await _userManager.CreateAsync(guestUser, "[email protected]");
            if (!result.Succeeded) return;

            if (await _roleManager.RoleExistsAsync("GuestRole"))
            {
                await _userManager.AddToRoleAsync(guestUser, "GuestRole");
            }
        }
  • modify Register-method of the controller
    • Add await CreateAdminAndGuest();-line as a first line of method. (It's for Demo)
        [HttpPost]
        [Route("api/[controller]/register")]
        public async Task<IActionResult> Register([FromBody] registerbindingmodel model)
        {
            await CreateAdminAndGuest();
            ...
        }
⚠️ **GitHub.com Fallback** ⚠️