From fdf286e22ff1950cd701dc4bffe127dbcea36a90 Mon Sep 17 00:00:00 2001 From: Tyler Wise Date: Sun, 13 Aug 2023 00:54:23 -0400 Subject: [PATCH] Auth endpoints are now functional --- src/IO.Swagger/Controllers/AuthApi.cs | 77 +++++++++++-------- src/IO.Swagger/Controllers/CurrencyApi.cs | 4 +- src/IO.Swagger/Controllers/WalletApi.cs | 4 +- src/IO.Swagger/IO.Swagger.csproj | 6 ++ ...0230813022042_Initial creation.Designer.cs | 60 +++++++++++++++ .../20230813022042_Initial creation.cs | 39 ++++++++++ ...230813022424_Change user table.Designer.cs | 59 ++++++++++++++ .../20230813022424_Change user table.cs | 68 ++++++++++++++++ .../Migrations/BankDbContextModelSnapshot.cs | 56 ++++++++++++++ src/IO.Swagger/Models/db/User.cs | 17 ++++ .../Models/{ => dto}/AuthLoginBody.cs | 20 ++--- .../Models/{ => dto}/AuthRegisterBody.cs | 42 +++++----- .../Models/{ => dto}/CurrencyAddAssetBody.cs | 28 +++---- .../Models/{ => dto}/CurrencyCreateBody.cs | 24 +++--- .../{ => dto}/CurrencyCreateCollectionBody.cs | 18 ++--- .../Models/{ => dto}/CurrencyMintBody.cs | 20 ++--- .../{ => dto}/WalletTransferDigitalBody.cs | 20 ++--- .../{ => dto}/WalletTransferPhysicalBody.cs | 26 +++---- src/IO.Swagger/Properties/launchSettings.json | 24 +++--- .../Repositories/IUserRepository.cs | 13 ++++ src/IO.Swagger/Repositories/UserRepository.cs | 77 +++++++++++++++++++ .../Security/BearerAuthenticationHandler.cs | 51 +++++++++--- src/IO.Swagger/Services/BankDbContext.cs | 17 ++++ src/IO.Swagger/Services/JwtService.cs | 46 +++++++++++ src/IO.Swagger/Startup.cs | 46 ++++++++++- src/IO.Swagger/web.config | 2 +- 26 files changed, 705 insertions(+), 159 deletions(-) create mode 100644 src/IO.Swagger/Migrations/20230813022042_Initial creation.Designer.cs create mode 100644 src/IO.Swagger/Migrations/20230813022042_Initial creation.cs create mode 100644 src/IO.Swagger/Migrations/20230813022424_Change user table.Designer.cs create mode 100644 src/IO.Swagger/Migrations/20230813022424_Change user table.cs create mode 100644 src/IO.Swagger/Migrations/BankDbContextModelSnapshot.cs create mode 100644 src/IO.Swagger/Models/db/User.cs rename src/IO.Swagger/Models/{ => dto}/AuthLoginBody.cs (92%) rename src/IO.Swagger/Models/{ => dto}/AuthRegisterBody.cs (85%) rename src/IO.Swagger/Models/{ => dto}/CurrencyAddAssetBody.cs (90%) rename src/IO.Swagger/Models/{ => dto}/CurrencyCreateBody.cs (90%) rename src/IO.Swagger/Models/{ => dto}/CurrencyCreateCollectionBody.cs (93%) rename src/IO.Swagger/Models/{ => dto}/CurrencyMintBody.cs (92%) rename src/IO.Swagger/Models/{ => dto}/WalletTransferDigitalBody.cs (92%) rename src/IO.Swagger/Models/{ => dto}/WalletTransferPhysicalBody.cs (91%) create mode 100644 src/IO.Swagger/Repositories/IUserRepository.cs create mode 100644 src/IO.Swagger/Repositories/UserRepository.cs create mode 100644 src/IO.Swagger/Services/BankDbContext.cs create mode 100644 src/IO.Swagger/Services/JwtService.cs diff --git a/src/IO.Swagger/Controllers/AuthApi.cs b/src/IO.Swagger/Controllers/AuthApi.cs index d7766cb..c25da70 100644 --- a/src/IO.Swagger/Controllers/AuthApi.cs +++ b/src/IO.Swagger/Controllers/AuthApi.cs @@ -17,16 +17,30 @@ using System.ComponentModel.DataAnnotations; using IO.Swagger.Attributes; using IO.Swagger.Security; using Microsoft.AspNetCore.Authorization; -using IO.Swagger.Models; +using IO.Swagger.Models.dto; +using IO.Swagger.Repositories; +using System.Threading.Tasks; +using System.Linq; +using IO.Swagger.Services; +using System.Security.Claims; namespace IO.Swagger.Controllers -{ +{ /// /// /// [ApiController] public class AuthApiController : ControllerBase - { + { + private readonly IUserRepository repository; + private readonly JwtService jwt; + + public AuthApiController(IUserRepository repository, JwtService jwt) + { + this.repository = repository ?? throw new ArgumentNullException(nameof(repository)); + this.jwt = jwt ?? throw new ArgumentNullException(nameof(jwt)); + } + /// /// Get user details /// @@ -37,15 +51,13 @@ namespace IO.Swagger.Controllers [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [ValidateModelState] [SwaggerOperation("GetUserDetails")] - public virtual IActionResult GetUserDetails() - { - //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(200); - - //TODO: Uncomment the next line to return response 401 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(401); - - throw new NotImplementedException(); + public virtual async Task GetUserDetails() + { + var userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; + if (!int.TryParse(userIdString, out int userId)) + return Unauthorized(); + var user = await repository.RetrieveUser(userId); + return user == null ? NoContent() : Ok(user); } /// @@ -58,40 +70,39 @@ namespace IO.Swagger.Controllers [Route("/v1/api/auth/login")] [ValidateModelState] [SwaggerOperation("LoginUser")] - public virtual IActionResult LoginUser([FromBody]AuthLoginBody body) - { - //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(200); - - //TODO: Uncomment the next line to return response 401 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(401); - - throw new NotImplementedException(); + public virtual async Task LoginUser([FromBody]AuthLoginBody body) + { + if (!ModelState.IsValid) + { + var errors = ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)); + return BadRequest(errors); + } + var user = await repository.LoginUser(body); + return user == null ? Unauthorized() : Ok(new { token = jwt.GenerateJwt(user.Id) }); } /// /// Register a new user /// /// - /// User registered successfully + /// User registered successfully /// Bad Request /// Conflict (user with provided email already exists) [HttpPost] [Route("/v1/api/auth/register")] [ValidateModelState] + [SwaggerOperation("RegisterUser")] - public virtual IActionResult RegisterUser([FromBody]AuthRegisterBody body) - { - //TODO: Uncomment the next line to return response 201 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(201); + public async Task RegisterUser([FromBody]AuthRegisterBody body) + { + if (!ModelState.IsValid) + { + var errors = ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)); + return BadRequest(errors); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400); - - //TODO: Uncomment the next line to return response 409 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(409); - - throw new NotImplementedException(); + var user = await repository.RegisterUser(body); + return user == null ? StatusCode(409) : Ok(new { token = jwt.GenerateJwt(user.Id) }); } } } diff --git a/src/IO.Swagger/Controllers/CurrencyApi.cs b/src/IO.Swagger/Controllers/CurrencyApi.cs index 1279c00..e04f389 100644 --- a/src/IO.Swagger/Controllers/CurrencyApi.cs +++ b/src/IO.Swagger/Controllers/CurrencyApi.cs @@ -17,10 +17,10 @@ using System.ComponentModel.DataAnnotations; using IO.Swagger.Attributes; using IO.Swagger.Security; using Microsoft.AspNetCore.Authorization; -using IO.Swagger.Models; +using IO.Swagger.Models.dto; namespace IO.Swagger.Controllers -{ +{ /// /// /// diff --git a/src/IO.Swagger/Controllers/WalletApi.cs b/src/IO.Swagger/Controllers/WalletApi.cs index 6c8c07e..0b22031 100644 --- a/src/IO.Swagger/Controllers/WalletApi.cs +++ b/src/IO.Swagger/Controllers/WalletApi.cs @@ -17,10 +17,10 @@ using System.ComponentModel.DataAnnotations; using IO.Swagger.Attributes; using IO.Swagger.Security; using Microsoft.AspNetCore.Authorization; -using IO.Swagger.Models; +using IO.Swagger.Models.dto; namespace IO.Swagger.Controllers -{ +{ /// /// /// diff --git a/src/IO.Swagger/IO.Swagger.csproj b/src/IO.Swagger/IO.Swagger.csproj index 77cf8af..854fe09 100644 --- a/src/IO.Swagger/IO.Swagger.csproj +++ b/src/IO.Swagger/IO.Swagger.csproj @@ -9,6 +9,12 @@ IO.Swagger + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/IO.Swagger/Migrations/20230813022042_Initial creation.Designer.cs b/src/IO.Swagger/Migrations/20230813022042_Initial creation.Designer.cs new file mode 100644 index 0000000..6ddcc00 --- /dev/null +++ b/src/IO.Swagger/Migrations/20230813022042_Initial creation.Designer.cs @@ -0,0 +1,60 @@ +// +using IO.Swagger.Services; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace IO.Swagger.Migrations +{ + [DbContext(typeof(BankDbContext))] + [Migration("20230813022042_Initial creation")] + partial class Initialcreation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("IO.Swagger.Models.db.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("Salt") + .HasColumnType("nvarchar(max)"); + + b.Property("Username") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs b/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs new file mode 100644 index 0000000..b9622b0 --- /dev/null +++ b/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace IO.Swagger.Migrations +{ + /// + public partial class Initialcreation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Email = table.Column(type: "nvarchar(max)", nullable: true), + FirstName = table.Column(type: "nvarchar(max)", nullable: true), + LastName = table.Column(type: "nvarchar(max)", nullable: true), + Username = table.Column(type: "nvarchar(max)", nullable: true), + PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), + Salt = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/src/IO.Swagger/Migrations/20230813022424_Change user table.Designer.cs b/src/IO.Swagger/Migrations/20230813022424_Change user table.Designer.cs new file mode 100644 index 0000000..06cc4bd --- /dev/null +++ b/src/IO.Swagger/Migrations/20230813022424_Change user table.Designer.cs @@ -0,0 +1,59 @@ +// +using IO.Swagger.Services; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace IO.Swagger.Migrations +{ + [DbContext(typeof(BankDbContext))] + [Migration("20230813022424_Change user table")] + partial class Changeusertable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("IO.Swagger.Models.db.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("LastName") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("Salt") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/IO.Swagger/Migrations/20230813022424_Change user table.cs b/src/IO.Swagger/Migrations/20230813022424_Change user table.cs new file mode 100644 index 0000000..0731987 --- /dev/null +++ b/src/IO.Swagger/Migrations/20230813022424_Change user table.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace IO.Swagger.Migrations +{ + /// + public partial class Changeusertable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Username", + table: "Users"); + + migrationBuilder.AlterColumn( + name: "LastName", + table: "Users", + type: "nvarchar(32)", + maxLength: 32, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "FirstName", + table: "Users", + type: "nvarchar(32)", + maxLength: 32, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "LastName", + table: "Users", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(32)", + oldMaxLength: 32, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "FirstName", + table: "Users", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(32)", + oldMaxLength: 32, + oldNullable: true); + + migrationBuilder.AddColumn( + name: "Username", + table: "Users", + type: "nvarchar(max)", + nullable: true); + } + } +} diff --git a/src/IO.Swagger/Migrations/BankDbContextModelSnapshot.cs b/src/IO.Swagger/Migrations/BankDbContextModelSnapshot.cs new file mode 100644 index 0000000..ca4ee56 --- /dev/null +++ b/src/IO.Swagger/Migrations/BankDbContextModelSnapshot.cs @@ -0,0 +1,56 @@ +// +using IO.Swagger.Services; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace IO.Swagger.Migrations +{ + [DbContext(typeof(BankDbContext))] + partial class BankDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("IO.Swagger.Models.db.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("LastName") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("Salt") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/IO.Swagger/Models/db/User.cs b/src/IO.Swagger/Models/db/User.cs new file mode 100644 index 0000000..9a9e29f --- /dev/null +++ b/src/IO.Swagger/Models/db/User.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace IO.Swagger.Models.db +{ + public class User + { + public int Id { get; set; } + public string Email { get; set; } + [StringLength(32, MinimumLength = 3)] + public string FirstName { get; set; } + [StringLength(32, MinimumLength = 3)] + public string LastName { get; set; } + public string PasswordHash { get; set; } + public string Salt { get; set; } + } + +} diff --git a/src/IO.Swagger/Models/AuthLoginBody.cs b/src/IO.Swagger/Models/dto/AuthLoginBody.cs similarity index 92% rename from src/IO.Swagger/Models/AuthLoginBody.cs rename to src/IO.Swagger/Models/dto/AuthLoginBody.cs index f821de0..b76d7e1 100644 --- a/src/IO.Swagger/Models/AuthLoginBody.cs +++ b/src/IO.Swagger/Models/dto/AuthLoginBody.cs @@ -18,26 +18,26 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class AuthLoginBody : IEquatable - { + { /// /// Gets or Sets Email /// - [DataMember(Name="email")] + [DataMember(Name = "email")] public string Email { get; set; } /// /// Gets or Sets Password /// - [DataMember(Name="password")] + [DataMember(Name = "password")] public string Password { get; set; } /// @@ -85,12 +85,12 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( Email == other.Email || Email != null && Email.Equals(other.Email) - ) && + ) && ( Password == other.Password || Password != null && @@ -108,16 +108,16 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (Email != null) + if (Email != null) hashCode = hashCode * 59 + Email.GetHashCode(); - if (Password != null) + if (Password != null) hashCode = hashCode * 59 + Password.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(AuthLoginBody left, AuthLoginBody right) { @@ -129,7 +129,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/AuthRegisterBody.cs b/src/IO.Swagger/Models/dto/AuthRegisterBody.cs similarity index 85% rename from src/IO.Swagger/Models/AuthRegisterBody.cs rename to src/IO.Swagger/Models/dto/AuthRegisterBody.cs index 1374ecf..ef2c3eb 100644 --- a/src/IO.Swagger/Models/AuthRegisterBody.cs +++ b/src/IO.Swagger/Models/dto/AuthRegisterBody.cs @@ -18,42 +18,48 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class AuthRegisterBody : IEquatable - { + { /// /// Gets or Sets FirstName /// - [StringLength(32, MinimumLength=3)] - [DataMember(Name="firstName")] + [StringLength(32, MinimumLength = 3)] + [DataMember(Name = "firstName")] + [Required] public string FirstName { get; set; } /// /// Gets or Sets LastName /// - [StringLength(32, MinimumLength=3)] - [DataMember(Name="lastName")] + [StringLength(32, MinimumLength = 3)] + [DataMember(Name = "lastName")] + [Required] public string LastName { get; set; } /// /// Gets or Sets Email /// - [DataMember(Name="email")] + [DataMember(Name = "email")] + [EmailAddress(ErrorMessage = "Invalid email format.")] + [Required] public string Email { get; set; } /// /// Gets or Sets Password /// - [DataMember(Name="password")] + [DataMember(Name = "password")] + [StringLength(32, MinimumLength = 8)] + [Required] public string Password { get; set; } /// @@ -103,22 +109,22 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( FirstName == other.FirstName || FirstName != null && FirstName.Equals(other.FirstName) - ) && + ) && ( LastName == other.LastName || LastName != null && LastName.Equals(other.LastName) - ) && + ) && ( Email == other.Email || Email != null && Email.Equals(other.Email) - ) && + ) && ( Password == other.Password || Password != null && @@ -136,20 +142,20 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (FirstName != null) + if (FirstName != null) hashCode = hashCode * 59 + FirstName.GetHashCode(); - if (LastName != null) + if (LastName != null) hashCode = hashCode * 59 + LastName.GetHashCode(); - if (Email != null) + if (Email != null) hashCode = hashCode * 59 + Email.GetHashCode(); - if (Password != null) + if (Password != null) hashCode = hashCode * 59 + Password.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(AuthRegisterBody left, AuthRegisterBody right) { @@ -161,7 +167,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/CurrencyAddAssetBody.cs b/src/IO.Swagger/Models/dto/CurrencyAddAssetBody.cs similarity index 90% rename from src/IO.Swagger/Models/CurrencyAddAssetBody.cs rename to src/IO.Swagger/Models/dto/CurrencyAddAssetBody.cs index db780c8..ab21642 100644 --- a/src/IO.Swagger/Models/CurrencyAddAssetBody.cs +++ b/src/IO.Swagger/Models/dto/CurrencyAddAssetBody.cs @@ -18,34 +18,34 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class CurrencyAddAssetBody : IEquatable - { + { /// /// Gets or Sets CollectionId /// - [DataMember(Name="collectionId")] + [DataMember(Name = "collectionId")] public int? CollectionId { get; set; } /// /// Gets or Sets AssetName /// - [StringLength(32, MinimumLength=1)] - [DataMember(Name="assetName")] + [StringLength(32, MinimumLength = 1)] + [DataMember(Name = "assetName")] public string AssetName { get; set; } /// /// Gets or Sets AssetLink /// [RegularExpression("/^(https?|ftp)://[^\\s/$.?#].[^\\s]*$/")] - [DataMember(Name="assetLink")] + [DataMember(Name = "assetLink")] public string AssetLink { get; set; } /// @@ -94,17 +94,17 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( CollectionId == other.CollectionId || CollectionId != null && CollectionId.Equals(other.CollectionId) - ) && + ) && ( AssetName == other.AssetName || AssetName != null && AssetName.Equals(other.AssetName) - ) && + ) && ( AssetLink == other.AssetLink || AssetLink != null && @@ -122,18 +122,18 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (CollectionId != null) + if (CollectionId != null) hashCode = hashCode * 59 + CollectionId.GetHashCode(); - if (AssetName != null) + if (AssetName != null) hashCode = hashCode * 59 + AssetName.GetHashCode(); - if (AssetLink != null) + if (AssetLink != null) hashCode = hashCode * 59 + AssetLink.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(CurrencyAddAssetBody left, CurrencyAddAssetBody right) { @@ -145,7 +145,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/CurrencyCreateBody.cs b/src/IO.Swagger/Models/dto/CurrencyCreateBody.cs similarity index 90% rename from src/IO.Swagger/Models/CurrencyCreateBody.cs rename to src/IO.Swagger/Models/dto/CurrencyCreateBody.cs index 0b506bf..092c278 100644 --- a/src/IO.Swagger/Models/CurrencyCreateBody.cs +++ b/src/IO.Swagger/Models/dto/CurrencyCreateBody.cs @@ -18,28 +18,28 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class CurrencyCreateBody : IEquatable - { + { /// /// Gets or Sets Name /// - [StringLength(32, MinimumLength=1)] - [DataMember(Name="name")] + [StringLength(32, MinimumLength = 1)] + [DataMember(Name = "name")] public string Name { get; set; } /// /// Gets or Sets Symbol /// - [StringLength(4, MinimumLength=1)] - [DataMember(Name="symbol")] + [StringLength(4, MinimumLength = 1)] + [DataMember(Name = "symbol")] public string Symbol { get; set; } /// @@ -87,12 +87,12 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( Name == other.Name || Name != null && Name.Equals(other.Name) - ) && + ) && ( Symbol == other.Symbol || Symbol != null && @@ -110,16 +110,16 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (Name != null) + if (Name != null) hashCode = hashCode * 59 + Name.GetHashCode(); - if (Symbol != null) + if (Symbol != null) hashCode = hashCode * 59 + Symbol.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(CurrencyCreateBody left, CurrencyCreateBody right) { @@ -131,7 +131,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/CurrencyCreateCollectionBody.cs b/src/IO.Swagger/Models/dto/CurrencyCreateCollectionBody.cs similarity index 93% rename from src/IO.Swagger/Models/CurrencyCreateCollectionBody.cs rename to src/IO.Swagger/Models/dto/CurrencyCreateCollectionBody.cs index 9d7f8b0..e0942c5 100644 --- a/src/IO.Swagger/Models/CurrencyCreateCollectionBody.cs +++ b/src/IO.Swagger/Models/dto/CurrencyCreateCollectionBody.cs @@ -18,19 +18,19 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class CurrencyCreateCollectionBody : IEquatable - { + { /// /// Gets or Sets CollectionName /// - [DataMember(Name="collectionName")] + [DataMember(Name = "collectionName")] public string CollectionName { get; set; } /// @@ -77,12 +77,12 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return - ( + return + CollectionName == other.CollectionName || CollectionName != null && CollectionName.Equals(other.CollectionName) - ); + ; } /// @@ -95,14 +95,14 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (CollectionName != null) + if (CollectionName != null) hashCode = hashCode * 59 + CollectionName.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(CurrencyCreateCollectionBody left, CurrencyCreateCollectionBody right) { @@ -114,7 +114,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/CurrencyMintBody.cs b/src/IO.Swagger/Models/dto/CurrencyMintBody.cs similarity index 92% rename from src/IO.Swagger/Models/CurrencyMintBody.cs rename to src/IO.Swagger/Models/dto/CurrencyMintBody.cs index 8ff6244..704da0d 100644 --- a/src/IO.Swagger/Models/CurrencyMintBody.cs +++ b/src/IO.Swagger/Models/dto/CurrencyMintBody.cs @@ -18,26 +18,26 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class CurrencyMintBody : IEquatable - { + { /// /// Gets or Sets CurrencyId /// - [DataMember(Name="currencyId")] + [DataMember(Name = "currencyId")] public int? CurrencyId { get; set; } /// /// Gets or Sets Amount /// - [DataMember(Name="amount")] + [DataMember(Name = "amount")] public decimal? Amount { get; set; } /// @@ -85,12 +85,12 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( CurrencyId == other.CurrencyId || CurrencyId != null && CurrencyId.Equals(other.CurrencyId) - ) && + ) && ( Amount == other.Amount || Amount != null && @@ -108,16 +108,16 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (CurrencyId != null) + if (CurrencyId != null) hashCode = hashCode * 59 + CurrencyId.GetHashCode(); - if (Amount != null) + if (Amount != null) hashCode = hashCode * 59 + Amount.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(CurrencyMintBody left, CurrencyMintBody right) { @@ -129,7 +129,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/WalletTransferDigitalBody.cs b/src/IO.Swagger/Models/dto/WalletTransferDigitalBody.cs similarity index 92% rename from src/IO.Swagger/Models/WalletTransferDigitalBody.cs rename to src/IO.Swagger/Models/dto/WalletTransferDigitalBody.cs index 358c7d2..6e3b5db 100644 --- a/src/IO.Swagger/Models/WalletTransferDigitalBody.cs +++ b/src/IO.Swagger/Models/dto/WalletTransferDigitalBody.cs @@ -18,26 +18,26 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class WalletTransferDigitalBody : IEquatable - { + { /// /// Gets or Sets Email /// - [DataMember(Name="email")] + [DataMember(Name = "email")] public string Email { get; set; } /// /// Gets or Sets AssetId /// - [DataMember(Name="assetId")] + [DataMember(Name = "assetId")] public int? AssetId { get; set; } /// @@ -85,12 +85,12 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( Email == other.Email || Email != null && Email.Equals(other.Email) - ) && + ) && ( AssetId == other.AssetId || AssetId != null && @@ -108,16 +108,16 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (Email != null) + if (Email != null) hashCode = hashCode * 59 + Email.GetHashCode(); - if (AssetId != null) + if (AssetId != null) hashCode = hashCode * 59 + AssetId.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(WalletTransferDigitalBody left, WalletTransferDigitalBody right) { @@ -129,7 +129,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Models/WalletTransferPhysicalBody.cs b/src/IO.Swagger/Models/dto/WalletTransferPhysicalBody.cs similarity index 91% rename from src/IO.Swagger/Models/WalletTransferPhysicalBody.cs rename to src/IO.Swagger/Models/dto/WalletTransferPhysicalBody.cs index 2233bcc..fca7ef9 100644 --- a/src/IO.Swagger/Models/WalletTransferPhysicalBody.cs +++ b/src/IO.Swagger/Models/dto/WalletTransferPhysicalBody.cs @@ -18,33 +18,33 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models.dto { /// /// /// [DataContract] public partial class WalletTransferPhysicalBody : IEquatable - { + { /// /// Gets or Sets Email /// - [DataMember(Name="email")] + [DataMember(Name = "email")] public string Email { get; set; } /// /// Gets or Sets Amount /// - [DataMember(Name="amount")] + [DataMember(Name = "amount")] public decimal? Amount { get; set; } /// /// Gets or Sets CurrencyId /// - [DataMember(Name="currencyId")] + [DataMember(Name = "currencyId")] public int? CurrencyId { get; set; } /// @@ -93,17 +93,17 @@ namespace IO.Swagger.Models if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return + return ( Email == other.Email || Email != null && Email.Equals(other.Email) - ) && + ) && ( Amount == other.Amount || Amount != null && Amount.Equals(other.Amount) - ) && + ) && ( CurrencyId == other.CurrencyId || CurrencyId != null && @@ -121,18 +121,18 @@ namespace IO.Swagger.Models { var hashCode = 41; // Suitable nullity checks etc, of course :) - if (Email != null) + if (Email != null) hashCode = hashCode * 59 + Email.GetHashCode(); - if (Amount != null) + if (Amount != null) hashCode = hashCode * 59 + Amount.GetHashCode(); - if (CurrencyId != null) + if (CurrencyId != null) hashCode = hashCode * 59 + CurrencyId.GetHashCode(); return hashCode; } } #region Operators - #pragma warning disable 1591 +#pragma warning disable 1591 public static bool operator ==(WalletTransferPhysicalBody left, WalletTransferPhysicalBody right) { @@ -144,7 +144,7 @@ namespace IO.Swagger.Models return !Equals(left, right); } - #pragma warning restore 1591 +#pragma warning restore 1591 #endregion Operators } } diff --git a/src/IO.Swagger/Properties/launchSettings.json b/src/IO.Swagger/Properties/launchSettings.json index 5bb6f82..b231764 100644 --- a/src/IO.Swagger/Properties/launchSettings.json +++ b/src/IO.Swagger/Properties/launchSettings.json @@ -1,12 +1,4 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:50352/", - "sslPort": 0 - } - }, "profiles": { "IIS Express": { "commandName": "IISExpress", @@ -20,10 +12,12 @@ "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } + "ASPNETCORE_ENVIRONMENT": "Development", + "DATABASE_CONNECTION_STRING": "Server=localhost\\SQLEXPRESS;Database=BankDb;Trusted_Connection=True;Integrated Security=True;TrustServerCertificate=True", + "JWT_SECRET_KEY": "mysuperduperubereepykeepysecretkey" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "Docker": { "commandName": "Docker", @@ -32,5 +26,13 @@ "publishAllPorts": true, "useSSL": true } + }, + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:50352/", + "sslPort": 0 + } } } \ No newline at end of file diff --git a/src/IO.Swagger/Repositories/IUserRepository.cs b/src/IO.Swagger/Repositories/IUserRepository.cs new file mode 100644 index 0000000..3796497 --- /dev/null +++ b/src/IO.Swagger/Repositories/IUserRepository.cs @@ -0,0 +1,13 @@ +using IO.Swagger.Models.db; +using IO.Swagger.Models.dto; +using System.Threading.Tasks; + +namespace IO.Swagger.Repositories +{ + public interface IUserRepository + { + Task LoginUser(AuthLoginBody request); + Task RegisterUser(AuthRegisterBody request); + Task RetrieveUser(int userId); + } +} diff --git a/src/IO.Swagger/Repositories/UserRepository.cs b/src/IO.Swagger/Repositories/UserRepository.cs new file mode 100644 index 0000000..856331e --- /dev/null +++ b/src/IO.Swagger/Repositories/UserRepository.cs @@ -0,0 +1,77 @@ +using IO.Swagger.Models.db; +using System.Security.Cryptography; +using System; +using IO.Swagger.Services; +using IO.Swagger.Models.dto; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using System.Linq; + +namespace IO.Swagger.Repositories +{ + public class UserRepository : IUserRepository + { + private readonly BankDbContext bankDbContext; + + public UserRepository(BankDbContext bankDbContext) + { + this.bankDbContext = bankDbContext; + } + + public async Task RegisterUser(AuthRegisterBody request) + { + request.Email = request.Email.ToLower(); + if (await bankDbContext.Users.CountAsync((User u) => u.Email == request.Email) > 0) + return null; + + // Generate a random salt + byte[] saltBytes = new byte[16]; + new RNGCryptoServiceProvider().GetBytes(saltBytes); + string salt = Convert.ToBase64String(saltBytes); + + // Hash the password along with the salt + string password = request.Password; + string saltedPassword = password + salt; + byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(saltedPassword); + byte[] hashedBytes = new SHA256Managed().ComputeHash(passwordBytes); + string hashedPassword = Convert.ToBase64String(hashedBytes); + + // Create and insert the user + var newUser = new User + { + PasswordHash = hashedPassword, + Salt = salt, + Email = request.Email, + FirstName = request.FirstName, + LastName = request.LastName + }; + + await bankDbContext.Users.AddAsync(newUser); + await bankDbContext.SaveChangesAsync(); + return newUser; + } + + public async Task LoginUser(AuthLoginBody request) + { + request.Email = request.Email.ToLower(); + var user = await bankDbContext.Users.FirstOrDefaultAsync(u => u.Email.Equals(request.Email)); + if (user == null) + return null; + + // Hash the supplied password with the retrieved salt + string password = request.Password; + string saltedPassword = password + user.Salt; + byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(saltedPassword); + byte[] hashedBytes = new SHA256Managed().ComputeHash(passwordBytes); + string hashedPassword = Convert.ToBase64String(hashedBytes); + if (hashedPassword != user.PasswordHash) + return null; + return user; + } + + public async Task RetrieveUser(int userId) + { + return await bankDbContext.Users.FirstOrDefaultAsync(u => u.Id == userId); + } + } +} diff --git a/src/IO.Swagger/Security/BearerAuthenticationHandler.cs b/src/IO.Swagger/Security/BearerAuthenticationHandler.cs index 15c7ab0..3e74eff 100644 --- a/src/IO.Swagger/Security/BearerAuthenticationHandler.cs +++ b/src/IO.Swagger/Security/BearerAuthenticationHandler.cs @@ -1,4 +1,6 @@ using System; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; using System.Net.Http.Headers; using System.Security.Claims; using System.Text; @@ -7,6 +9,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json.Linq; namespace IO.Swagger.Security { @@ -15,6 +19,9 @@ namespace IO.Swagger.Security /// public class BearerAuthenticationHandler : AuthenticationHandler { + private readonly string secretKey; + private readonly byte[] secretBytes; + /// /// scheme name for authentication handler. /// @@ -22,6 +29,8 @@ namespace IO.Swagger.Security public BearerAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { + secretKey = Environment.GetEnvironmentVariable("JWT_SECRET_KEY"); + secretBytes = Encoding.UTF8.GetBytes(secretKey); } /// @@ -37,22 +46,44 @@ namespace IO.Swagger.Security { var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); - /// TODO handle token. + var tokenHandler = new JwtSecurityTokenHandler(); + var validationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(secretBytes), + ValidateIssuer = false, + ValidateAudience = false + }; + + try + { + var claimsPrincipal = tokenHandler.ValidateToken(authHeader.Parameter, validationParameters, out _); + var userIdClaim = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier); + + if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId)) + { + var claims = new[]{ new Claim(ClaimTypes.NameIdentifier, userId.ToString()) }; + var identity = new ClaimsIdentity(claims, SchemeName); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + } + catch (Exception) + { + return AuthenticateResult.Fail("Invalid Auth Token"); + } + + + } catch { return AuthenticateResult.Fail("Invalid Authorization Header"); } - var claims = new[] { - new Claim(ClaimTypes.NameIdentifier, "changeme"), - new Claim(ClaimTypes.Name, "changeme"), - }; - var identity = new ClaimsIdentity(claims, Scheme.Name); - var principal = new ClaimsPrincipal(identity); - var ticket = new AuthenticationTicket(principal, Scheme.Name); - - return AuthenticateResult.Success(ticket); + return AuthenticateResult.Fail("Missing Authorization Header"); } } } diff --git a/src/IO.Swagger/Services/BankDbContext.cs b/src/IO.Swagger/Services/BankDbContext.cs new file mode 100644 index 0000000..71e0528 --- /dev/null +++ b/src/IO.Swagger/Services/BankDbContext.cs @@ -0,0 +1,17 @@ +using IO.Swagger.Models.db; +using Microsoft.EntityFrameworkCore; + +namespace IO.Swagger.Services +{ + + public class BankDbContext : DbContext + { + public BankDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Users { get; set; } + + + } +} diff --git a/src/IO.Swagger/Services/JwtService.cs b/src/IO.Swagger/Services/JwtService.cs new file mode 100644 index 0000000..ffbd279 --- /dev/null +++ b/src/IO.Swagger/Services/JwtService.cs @@ -0,0 +1,46 @@ +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using System; + +namespace IO.Swagger.Services +{ + public class JwtService + { + private readonly string secretKey; + private readonly byte[] secretBytes; + + public JwtService() + { + secretKey = Environment.GetEnvironmentVariable("JWT_SECRET_KEY"); + secretBytes = Encoding.UTF8.GetBytes(secretKey); + } + + public string GenerateJwt(int userId) + { + var claims = new[] + { + new Claim(ClaimTypes.NameIdentifier, userId.ToString()) + // You can add more claims as needed + }; + + var tokenHandler = new JwtSecurityTokenHandler(); + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(claims), + Expires = DateTime.UtcNow.AddHours(1), // Token expiration time + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(secretBytes), SecurityAlgorithms.HmacSha256Signature) + }; + + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } + + public int GetUserIdFromJwt(string jwtToken) + { + + return -1; // Return -1 if user ID extraction fails + } + } +} diff --git a/src/IO.Swagger/Startup.cs b/src/IO.Swagger/Startup.cs index 9a497e9..2f65e9b 100644 --- a/src/IO.Swagger/Startup.cs +++ b/src/IO.Swagger/Startup.cs @@ -23,6 +23,9 @@ using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using IO.Swagger.Filters; using IO.Swagger.Security; +using IO.Swagger.Repositories; +using IO.Swagger.Services; +using Microsoft.EntityFrameworkCore; namespace IO.Swagger { @@ -80,9 +83,9 @@ namespace IO.Swagger Description = "T&J Central Bank API (ASP.NET 7.0)", Contact = new OpenApiContact() { - Name = "Swagger Codegen Contributors", - Url = new Uri("https://github.com/swagger-api/swagger-codegen"), - Email = "" + Name = "Swagger Codegen Contributors", + Url = new Uri("https://github.com/swagger-api/swagger-codegen"), + Email = "" }, // TermsOfService = new Uri("") }); @@ -94,7 +97,40 @@ namespace IO.Swagger // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) // Use [ValidateModelState] on Actions to actually validate it in C# as well! c.OperationFilter(); + c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme() + { + In = ParameterLocation.Header, + Description = "Please enter a valid token", + Name = "Authorization", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT", + Scheme = "bearer" + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement() + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type=ReferenceType.SecurityScheme, + Id="bearerAuth" + } + }, + new string[]{} + } + }); }); + + string connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_STRING"); + + if (string.IsNullOrEmpty(connectionString)) + { + throw new Exception("Database connection string not found in environment variable."); + } + services.AddScoped(); + services.AddDbContext(x => x.UseSqlServer(connectionString: connectionString)); + services.AddSingleton(); } /// @@ -103,8 +139,10 @@ namespace IO.Swagger /// /// /// - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, BankDbContext context) { + context.Database.Migrate(); app.UseRouting(); //TODO: Uncomment this if you need wwwroot folder diff --git a/src/IO.Swagger/web.config b/src/IO.Swagger/web.config index 2c68e3c..c846261 100644 --- a/src/IO.Swagger/web.config +++ b/src/IO.Swagger/web.config @@ -17,7 +17,7 @@ - +