From 78dba75e03871c9d6377f50a6942fa9b490ee842 Mon Sep 17 00:00:00 2001 From: Hai Chi Date: Sat, 9 Dec 2023 15:57:32 +0800 Subject: [PATCH] Implement Authentication --- taskmaster-api/Controllers/AuthController.cs | 40 +++ taskmaster-api/Controllers/TaskController.cs | 24 +- .../Data/Contexts/ApplicationDbContext.cs | 6 +- taskmaster-api/Data/DTOs/LoginDto.cs | 13 + taskmaster-api/Data/DTOs/LoginResponseDto.cs | 8 + taskmaster-api/Data/DTOs/RegisterDto.cs | 17 + taskmaster-api/Data/Entities/UserEntity.cs | 23 -- taskmaster-api/Data/Models/UserRoles.cs | 8 + .../20231207132920_InitialCreate.Designer.cs | 75 ---- .../20231207132920_InitialCreate.cs | 54 --- .../20231208193605_InitialCreate.Designer.cs | 324 ++++++++++++++++++ .../20231208193605_InitialCreate.cs | 259 ++++++++++++++ .../ApplicationDbContextModelSnapshot.cs | 253 +++++++++++++- taskmaster-api/Program.cs | 54 ++- taskmaster-api/Services/AuthService.cs | 160 +++++++++ .../Services/Interface/IAuthService.cs | 12 + .../{ITaskAppService.cs => ITaskService.cs} | 2 +- .../{TaskAppService.cs => TaskService.cs} | 4 +- taskmaster-api/appsettings.json | 6 + taskmaster-api/taskmaster-api.csproj | 6 +- 20 files changed, 1166 insertions(+), 182 deletions(-) create mode 100644 taskmaster-api/Controllers/AuthController.cs create mode 100644 taskmaster-api/Data/DTOs/LoginDto.cs create mode 100644 taskmaster-api/Data/DTOs/LoginResponseDto.cs create mode 100644 taskmaster-api/Data/DTOs/RegisterDto.cs delete mode 100644 taskmaster-api/Data/Entities/UserEntity.cs create mode 100644 taskmaster-api/Data/Models/UserRoles.cs delete mode 100644 taskmaster-api/Migrations/20231207132920_InitialCreate.Designer.cs delete mode 100644 taskmaster-api/Migrations/20231207132920_InitialCreate.cs create mode 100644 taskmaster-api/Migrations/20231208193605_InitialCreate.Designer.cs create mode 100644 taskmaster-api/Migrations/20231208193605_InitialCreate.cs create mode 100644 taskmaster-api/Services/AuthService.cs create mode 100644 taskmaster-api/Services/Interface/IAuthService.cs rename taskmaster-api/Services/Interface/{ITaskAppService.cs => ITaskService.cs} (92%) rename taskmaster-api/Services/{TaskAppService.cs => TaskService.cs} (96%) diff --git a/taskmaster-api/Controllers/AuthController.cs b/taskmaster-api/Controllers/AuthController.cs new file mode 100644 index 0000000..0610bdd --- /dev/null +++ b/taskmaster-api/Controllers/AuthController.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using taskmaster_api.Data.DTOs; +using taskmaster_api.Services.Interface; + +namespace taskmaster_api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class AuthController : ApplicationControllerBase + { + private readonly IAuthService _authService; + + public AuthController(IAuthService authService) + { + _authService = authService; + } + + [HttpPost("login")] + [AllowAnonymous] + public IActionResult Login(LoginDto loginDto) + { + return ToHttpResult(_authService.Login(loginDto)); + } + + [HttpPost("register")] + [AllowAnonymous] + public IActionResult Register(RegisterDto registerDto) + { + return ToHttpResult(_authService.Register(registerDto)); + } + + [HttpPost("register-admin")] + [AllowAnonymous] + public IActionResult RegisterAdmin(RegisterDto registerDto) + { + return ToHttpResult(_authService.RegisterAdmin(registerDto)); + } + } +} diff --git a/taskmaster-api/Controllers/TaskController.cs b/taskmaster-api/Controllers/TaskController.cs index f681076..036381c 100644 --- a/taskmaster-api/Controllers/TaskController.cs +++ b/taskmaster-api/Controllers/TaskController.cs @@ -1,11 +1,7 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using taskmaster_api.Data.DTOs; -using taskmaster_api.Data.DTOs.Interface; -using taskmaster_api.Data.Entities; -using taskmaster_api.Data.Repositories.Interface; -using taskmaster_api.Services; +using taskmaster_api.Data.Models; using taskmaster_api.Services.Interface; namespace taskmaster_api.Controllers @@ -14,35 +10,37 @@ namespace taskmaster_api.Controllers [ApiController] public class TaskController : ApplicationControllerBase { - private readonly ITaskAppService _taskAppService; + private readonly ITaskService _taskService; - public TaskController(ITaskAppService taskAppService) + public TaskController(ITaskService taskService) { - _taskAppService = taskAppService; + _taskService = taskService; } [HttpGet("{id}")] + [Authorize] public IActionResult GetTask(int id) { - return ToHttpResult(_taskAppService.GetTaskById(id)); + return ToHttpResult(_taskService.GetTaskById(id)); } [HttpPost] public IActionResult CreateTask(TaskDto taskDto) { - return ToHttpResult(_taskAppService.CreateTask(taskDto)); + return ToHttpResult(_taskService.CreateTask(taskDto)); } [HttpPut("{id}")] + [Authorize(Roles = UserRoles.Admin)] public IActionResult UpdateTask(int id, TaskDto taskDto) { - return ToHttpResult(_taskAppService.UpdateTask(id, taskDto)); + return ToHttpResult(_taskService.UpdateTask(id, taskDto)); } [HttpDelete("{id}")] public IActionResult DeleteTask(int id) { - return ToHttpResult(_taskAppService.DeleteTask(id)); + return ToHttpResult(_taskService.DeleteTask(id)); } } } diff --git a/taskmaster-api/Data/Contexts/ApplicationDbContext.cs b/taskmaster-api/Data/Contexts/ApplicationDbContext.cs index 5e9e6de..c13ac0a 100644 --- a/taskmaster-api/Data/Contexts/ApplicationDbContext.cs +++ b/taskmaster-api/Data/Contexts/ApplicationDbContext.cs @@ -1,15 +1,15 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using taskmaster_api.Data.Entities; namespace taskmaster_api.Data.Contexts { - public class ApplicationDbContext : DbContext + public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext(DbContextOptions options) : base(options) { } - public virtual DbSet Users { get; set; } public virtual DbSet Tasks { get; set; } } } diff --git a/taskmaster-api/Data/DTOs/LoginDto.cs b/taskmaster-api/Data/DTOs/LoginDto.cs new file mode 100644 index 0000000..ce6e837 --- /dev/null +++ b/taskmaster-api/Data/DTOs/LoginDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace taskmaster_api.Data.DTOs +{ + public class LoginDto + { + [Required(ErrorMessage = "User Name is required")] + public string? Username { get; set; } + + [Required(ErrorMessage = "Password is required")] + public string? Password { get; set; } + } +} diff --git a/taskmaster-api/Data/DTOs/LoginResponseDto.cs b/taskmaster-api/Data/DTOs/LoginResponseDto.cs new file mode 100644 index 0000000..1d41718 --- /dev/null +++ b/taskmaster-api/Data/DTOs/LoginResponseDto.cs @@ -0,0 +1,8 @@ +namespace taskmaster_api.Data.DTOs +{ + public class LoginResponseDto + { + public string Token { get; set; } + public DateTime Expiration { get; set; } + } +} diff --git a/taskmaster-api/Data/DTOs/RegisterDto.cs b/taskmaster-api/Data/DTOs/RegisterDto.cs new file mode 100644 index 0000000..6fd4f97 --- /dev/null +++ b/taskmaster-api/Data/DTOs/RegisterDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace taskmaster_api.Data.DTOs +{ + public class RegisterDto + { + [Required(ErrorMessage = "User Name is required")] + public string? Username { get; set; } + + [EmailAddress] + [Required(ErrorMessage = "Email is required")] + public string? Email { get; set; } + + [Required(ErrorMessage = "Password is required")] + public string? Password { get; set; } + } +} diff --git a/taskmaster-api/Data/Entities/UserEntity.cs b/taskmaster-api/Data/Entities/UserEntity.cs deleted file mode 100644 index 203e3b3..0000000 --- a/taskmaster-api/Data/Entities/UserEntity.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using taskmaster_api.Data.DTOs; -using taskmaster_api.Data.Entities.Interface; -using taskmaster_api.Utilities; - -namespace taskmaster_api.Data.Entities -{ - public class UserEntity: IEntity - { - [Key] - public int Id { get; set; } - - [Required] - public string Username { get; set; } - - public string Email { get; set; } - - public UserDto ToDto() - { - return EntityHelpers.ToDto(this); - } - } -} diff --git a/taskmaster-api/Data/Models/UserRoles.cs b/taskmaster-api/Data/Models/UserRoles.cs new file mode 100644 index 0000000..a1a0831 --- /dev/null +++ b/taskmaster-api/Data/Models/UserRoles.cs @@ -0,0 +1,8 @@ +namespace taskmaster_api.Data.Models +{ + public static class UserRoles + { + public const string Admin = "Admin"; + public const string User = "User"; + } +} diff --git a/taskmaster-api/Migrations/20231207132920_InitialCreate.Designer.cs b/taskmaster-api/Migrations/20231207132920_InitialCreate.Designer.cs deleted file mode 100644 index 3606699..0000000 --- a/taskmaster-api/Migrations/20231207132920_InitialCreate.Designer.cs +++ /dev/null @@ -1,75 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using taskmaster_api.Data.Contexts; - -#nullable disable - -namespace taskmaster_api.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20231207132920_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.0") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("taskmaster_api.Data.Entities.Task", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Description") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("DueDate") - .HasColumnType("datetime2"); - - b.Property("Title") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("Tasks"); - }); - - modelBuilder.Entity("taskmaster_api.Data.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Email") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("Username") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/taskmaster-api/Migrations/20231207132920_InitialCreate.cs b/taskmaster-api/Migrations/20231207132920_InitialCreate.cs deleted file mode 100644 index 6dec3c5..0000000 --- a/taskmaster-api/Migrations/20231207132920_InitialCreate.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace taskmaster_api.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Tasks", - columns: table => new - { - Id = table.Column(type: "int", nullable: false) - .Annotation("SqlServer:Identity", "1, 1"), - Title = table.Column(type: "nvarchar(max)", nullable: false), - Description = table.Column(type: "nvarchar(max)", nullable: false), - DueDate = table.Column(type: "datetime2", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Tasks", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Users", - columns: table => new - { - Id = table.Column(type: "int", nullable: false) - .Annotation("SqlServer:Identity", "1, 1"), - Username = table.Column(type: "nvarchar(max)", nullable: false), - Email = table.Column(type: "nvarchar(max)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Users", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Tasks"); - - migrationBuilder.DropTable( - name: "Users"); - } - } -} diff --git a/taskmaster-api/Migrations/20231208193605_InitialCreate.Designer.cs b/taskmaster-api/Migrations/20231208193605_InitialCreate.Designer.cs new file mode 100644 index 0000000..403e300 --- /dev/null +++ b/taskmaster-api/Migrations/20231208193605_InitialCreate.Designer.cs @@ -0,0 +1,324 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using taskmaster_api.Data.Contexts; + +#nullable disable + +namespace taskmaster_api.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20231208193605_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("taskmaster_api.Data.Entities.TaskEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Tasks"); + }); + + modelBuilder.Entity("taskmaster_api.Data.Entities.UserEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/taskmaster-api/Migrations/20231208193605_InitialCreate.cs b/taskmaster-api/Migrations/20231208193605_InitialCreate.cs new file mode 100644 index 0000000..2ff02d2 --- /dev/null +++ b/taskmaster-api/Migrations/20231208193605_InitialCreate.cs @@ -0,0 +1,259 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace taskmaster_api.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "bit", nullable: false), + PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), + SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), + TwoFactorEnabled = table.Column(type: "bit", nullable: false), + LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), + LockoutEnabled = table.Column(type: "bit", nullable: false), + AccessFailedCount = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Tasks", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Title = table.Column(type: "nvarchar(max)", nullable: false), + Description = table.Column(type: "nvarchar(max)", nullable: false), + DueDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tasks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Username = table.Column(type: "nvarchar(max)", nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + RoleId = table.Column(type: "nvarchar(450)", nullable: false), + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "nvarchar(450)", nullable: false), + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), + ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), + ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), + UserId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "nvarchar(450)", nullable: false), + RoleId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "nvarchar(450)", nullable: false), + LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Value = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true, + filter: "[NormalizedName] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true, + filter: "[NormalizedUserName] IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "Tasks"); + + migrationBuilder.DropTable( + name: "Users"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/taskmaster-api/Migrations/ApplicationDbContextModelSnapshot.cs b/taskmaster-api/Migrations/ApplicationDbContextModelSnapshot.cs index 02859bb..d3637dc 100644 --- a/taskmaster-api/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/taskmaster-api/Migrations/ApplicationDbContextModelSnapshot.cs @@ -22,7 +22,205 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - modelBuilder.Entity("taskmaster_api.Data.Entities.Task", b => + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("taskmaster_api.Data.Entities.TaskEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -46,7 +244,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Tasks"); }); - modelBuilder.Entity("taskmaster_api.Data.Entities.User", b => + modelBuilder.Entity("taskmaster_api.Data.Entities.UserEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -66,6 +264,57 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Users"); }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); #pragma warning restore 612, 618 } } diff --git a/taskmaster-api/Program.cs b/taskmaster-api/Program.cs index 15372cc..467ac57 100644 --- a/taskmaster-api/Program.cs +++ b/taskmaster-api/Program.cs @@ -4,10 +4,11 @@ using taskmaster_api.Data.Repositories.Interface; using taskmaster_api.Services.Interface; using taskmaster_api.Services; -using taskmaster_api.Data.DTOs.Interface; -using taskmaster_api.Data.DTOs; -using taskmaster_api.Data.Entities; -using taskmaster_api.Data.Entities.Interface; +using Microsoft.AspNetCore.Identity; +using Swashbuckle.AspNetCore.Filters; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; var builder = WebApplication.CreateBuilder(args); @@ -16,15 +17,51 @@ builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +builder.Services.AddSwaggerGen(options => +{ + options.AddSecurityDefinition("oauth2", new Microsoft.OpenApi.Models.OpenApiSecurityScheme + { + In = Microsoft.OpenApi.Models.ParameterLocation.Header, + Name = "Authorization", + Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey + }); + + options.OperationFilter(); +}); -builder.Services.AddDbContext(options => { +builder.Services.AddDbContext(options => +{ options.UseSqlServer(builder.Configuration.GetConnectionString("AppDbConnection")); }); -builder.Services.AddScoped(); +builder.Services.AddAuthorization(); +builder.Services.AddIdentity() + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); -builder.Services.AddScoped(); +builder.Services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; +}) +.AddJwtBearer(options => +{ + options.SaveToken = true; + options.RequireHttpsMetadata = false; + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = true, + ValidateAudience = true, + ValidAudience = builder.Configuration["JWT:ValidAudience"], + ValidIssuer = builder.Configuration["JWT:ValidIssuer"], + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"])) + }; +}); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); var app = builder.Build(); @@ -37,6 +74,7 @@ app.UseHttpsRedirection(); +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/taskmaster-api/Services/AuthService.cs b/taskmaster-api/Services/AuthService.cs new file mode 100644 index 0000000..c26a93e --- /dev/null +++ b/taskmaster-api/Services/AuthService.cs @@ -0,0 +1,160 @@ +using taskmaster_api.Data.DTOs.Interface; +using taskmaster_api.Data.DTOs; +using taskmaster_api.Services.Interface; +using System.Security.Claims; +using Microsoft.AspNetCore.Identity; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using taskmaster_api.Data.Models; + +namespace taskmaster_api.Services +{ + public class AuthService : IAuthService + { + private readonly UserManager _userManager; + private readonly RoleManager _roleManager; + private readonly IConfiguration _configuration; + + public AuthService(UserManager userManager, RoleManager roleManager, IConfiguration configuration) + { + _userManager = userManager; + _roleManager = roleManager; + _configuration = configuration; + } + + public ICoreActionResult Login(LoginDto loginDto) + { + try + { + var user = _userManager.FindByNameAsync(loginDto.Username).Result; + if (user != null && _userManager.CheckPasswordAsync(user, loginDto.Password).Result) + { + var userRoles = _userManager.GetRolesAsync(user).Result; + + var authClaims = new List + { + new Claim(ClaimTypes.Name, user.UserName), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + }; + + foreach (var userRole in userRoles) + { + authClaims.Add(new Claim(ClaimTypes.Role, userRole)); + } + + var token = GetToken(authClaims); + + return CoreActionResult.Success(new LoginResponseDto + { + Token = new JwtSecurityTokenHandler().WriteToken(token), + Expiration = token.ValidTo, + }); + } + + return CoreActionResult.Failure("Login Failed."); + } + catch (Exception ex) + { + return CoreActionResult.Exception(ex); + } + } + + public ICoreActionResult Register(RegisterDto registerDto) + { + try + { + var userExists = _userManager.FindByNameAsync(registerDto.Username).Result; + if (userExists != null) + { + return CoreActionResult.Failure("User already exists!"); + } + + IdentityUser user = new() + { + Email = registerDto.Email, + SecurityStamp = Guid.NewGuid().ToString(), + UserName = registerDto.Username + }; + var result = _userManager.CreateAsync(user, registerDto.Password).Result; + + if (!result.Succeeded) + { + return CoreActionResult.Failure("User creation failed! Please check user details and try again."); + } + + return CoreActionResult.Success(registerDto); + } + catch (Exception ex) + { + return CoreActionResult.Exception(ex); + } + } + + public ICoreActionResult RegisterAdmin(RegisterDto registerDto) + { + try + { + var userExists = _userManager.FindByNameAsync(registerDto.Username).Result; + if (userExists != null) + { + return CoreActionResult.Failure("User already exists!"); + } + + IdentityUser user = new() + { + Email = registerDto.Email, + SecurityStamp = Guid.NewGuid().ToString(), + UserName = registerDto.Username + }; + + var result = _userManager.CreateAsync(user, registerDto.Password).Result; + if (!result.Succeeded) + { + return CoreActionResult.Failure("User creation failed! Please check user details and try again."); + } + + if (!_roleManager.RoleExistsAsync(UserRoles.Admin).Result) + { + var adminIdentityResult = _roleManager.CreateAsync(new IdentityRole(UserRoles.Admin)).Result; + } + + if (!_roleManager.RoleExistsAsync(UserRoles.User).Result) + { + var userIdentityResult = _roleManager.CreateAsync(new IdentityRole(UserRoles.User)).Result; + } + + if (_roleManager.RoleExistsAsync(UserRoles.Admin).Result) + { + var adminIdentityResult = _userManager.AddToRoleAsync(user, UserRoles.Admin).Result; + } + + if (_roleManager.RoleExistsAsync(UserRoles.Admin).Result) + { + var userIdentityResult = _userManager.AddToRoleAsync(user, UserRoles.User).Result; + } + + return CoreActionResult.Success(registerDto); + } + catch (Exception ex) + { + return CoreActionResult.Exception(ex); + } + } + + private JwtSecurityToken GetToken(List authClaims) + { + var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"])); + + var token = new JwtSecurityToken( + issuer: _configuration["JWT:ValidIssuer"], + audience: _configuration["JWT:ValidAudience"], + expires: DateTime.Now.AddMinutes(double.Parse(_configuration["JWT:DurationInMinutes"])), + claims: authClaims, + signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) + ); + + return token; + } + } +} diff --git a/taskmaster-api/Services/Interface/IAuthService.cs b/taskmaster-api/Services/Interface/IAuthService.cs new file mode 100644 index 0000000..f8c7b46 --- /dev/null +++ b/taskmaster-api/Services/Interface/IAuthService.cs @@ -0,0 +1,12 @@ +using taskmaster_api.Data.DTOs.Interface; +using taskmaster_api.Data.DTOs; + +namespace taskmaster_api.Services.Interface +{ + public interface IAuthService + { + ICoreActionResult Login(LoginDto loginDto); + ICoreActionResult Register(RegisterDto registerDto); + ICoreActionResult RegisterAdmin(RegisterDto registerDto); + } +} diff --git a/taskmaster-api/Services/Interface/ITaskAppService.cs b/taskmaster-api/Services/Interface/ITaskService.cs similarity index 92% rename from taskmaster-api/Services/Interface/ITaskAppService.cs rename to taskmaster-api/Services/Interface/ITaskService.cs index d524150..b2df114 100644 --- a/taskmaster-api/Services/Interface/ITaskAppService.cs +++ b/taskmaster-api/Services/Interface/ITaskService.cs @@ -4,7 +4,7 @@ namespace taskmaster_api.Services.Interface { - public interface ITaskAppService + public interface ITaskService { ICoreActionResult GetTaskById(int id); ICoreActionResult> GetAllTasks(); diff --git a/taskmaster-api/Services/TaskAppService.cs b/taskmaster-api/Services/TaskService.cs similarity index 96% rename from taskmaster-api/Services/TaskAppService.cs rename to taskmaster-api/Services/TaskService.cs index 1cd1bd8..ca8458a 100644 --- a/taskmaster-api/Services/TaskAppService.cs +++ b/taskmaster-api/Services/TaskService.cs @@ -7,11 +7,11 @@ namespace taskmaster_api.Services { - public class TaskAppService : ITaskAppService + public class TaskService : ITaskService { private readonly ITaskRepository _taskRepository; - public TaskAppService(ITaskRepository taskRepository) + public TaskService(ITaskRepository taskRepository) { _taskRepository = taskRepository; } diff --git a/taskmaster-api/appsettings.json b/taskmaster-api/appsettings.json index bdbcf09..7821c9f 100644 --- a/taskmaster-api/appsettings.json +++ b/taskmaster-api/appsettings.json @@ -8,5 +8,11 @@ "AllowedHosts": "*", "ConnectionStrings": { "AppDbConnection": "Server=Admin\\SQL2022;Database=TaskMaster;User Id=sa;Password=ms2023*;MultipleActiveResultSets=true;Encrypt=false" + }, + "JWT": { + "ValidAudience": "http://localhost:4200", + "ValidIssuer": "http://localhost:5000", + "Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr", + "DurationInMinutes": 180 } } diff --git a/taskmaster-api/taskmaster-api.csproj b/taskmaster-api/taskmaster-api.csproj index 17d487a..1838c4a 100644 --- a/taskmaster-api/taskmaster-api.csproj +++ b/taskmaster-api/taskmaster-api.csproj @@ -9,6 +9,8 @@ + + all @@ -19,7 +21,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + + +