Session wip
This commit is contained in:
parent
e0e9df2edd
commit
3b8d82049f
|
@ -12,16 +12,18 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="6.0.2" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.49.0-pre1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authorization.Policy" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization.Policy" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.2">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\BlueWest.Data.Application\BlueWest.Data.Application.csproj" />
|
||||||
<ProjectReference Include="..\BlueWest.Data.Capital\BlueWest.Data.Capital.csproj" />
|
<ProjectReference Include="..\BlueWest.Data.Capital\BlueWest.Data.Capital.csproj" />
|
||||||
<ProjectReference Include="..\BlueWest\BlueWest.csproj" />
|
<ProjectReference Include="..\BlueWest\BlueWest.csproj" />
|
||||||
<ProjectReference Include="..\include\BlueWest.EfMethods\src\BlueWest.EfMethods\BlueWest.EfMethods.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\include\BlueWest.EfMethods\src\BlueWest.EfMethods\BlueWest.EfMethods.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
|
|
|
@ -25,25 +25,24 @@ namespace BlueWest.WebApi.Context
|
||||||
[EfGetMany(typeof(ApplicationUserClaimUnique))]
|
[EfGetMany(typeof(ApplicationUserClaimUnique))]
|
||||||
public sealed override DbSet<ApplicationUserClaim> UserClaims { get; set; }
|
public sealed override DbSet<ApplicationUserClaim> UserClaims { get; set; }
|
||||||
|
|
||||||
[EfGetMany(typeof(ApplicationUserRoleUnique))]
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[EfGetMany(typeof(ApplicationUserRoleUnique))]
|
||||||
public sealed override DbSet<ApplicationUserRole> UserRoles { get; set; }
|
public sealed override DbSet<ApplicationUserRole> UserRoles { get; set; }
|
||||||
|
|
||||||
[EfGetMany(typeof(ApplicationRoleUnique))]
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[EfGetMany(typeof(ApplicationRoleUnique))]
|
||||||
public sealed override DbSet<ApplicationRole> Roles { get; set; }
|
public sealed override DbSet<ApplicationRole> Roles { get; set; }
|
||||||
|
|
||||||
[EfGetMany(typeof(ApplicationRoleClaimUnique))]
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[EfGetMany(typeof(ApplicationRoleClaimUnique))]
|
||||||
public sealed override DbSet<ApplicationRoleClaim> RoleClaims { get; set; }
|
public sealed override DbSet<ApplicationRoleClaim> RoleClaims { get; set; }
|
||||||
|
|
||||||
[EfGetMany(typeof(ApplicationUserUnique))]
|
[EfGetMany(typeof(ApplicationUserUnique))]
|
||||||
[EfUpdateMethods( updateType: typeof(ApplicationUserUnique), returnType: typeof(ApplicationUserUnique), keyPropertyMemberName: nameof(ApplicationUserUnique.Id))]
|
[EfUpdateMethods( updateType: typeof(ApplicationUserUnique), returnType: typeof(ApplicationUserUnique), keyPropertyMemberName: nameof(ApplicationUserUnique.Id))]
|
||||||
public sealed override DbSet<ApplicationUser> Users { get; set; }
|
public sealed override DbSet<ApplicationUser> Users { get; set; }
|
||||||
|
|
||||||
#region Initialization
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
#region Initialization
|
||||||
public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options) : base(options)
|
public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options) : base(options)
|
||||||
{
|
{
|
||||||
Database.EnsureCreated();
|
Database.EnsureCreated();
|
||||||
|
@ -55,62 +54,13 @@ namespace BlueWest.WebApi.Context
|
||||||
{
|
{
|
||||||
base.OnModelCreating(builder);
|
base.OnModelCreating(builder);
|
||||||
|
|
||||||
builder.Entity<ApplicationUserRole>().ToTable("UserRoles");
|
|
||||||
builder.Entity<ApplicationUser>(b =>
|
|
||||||
{
|
|
||||||
b.HasMany<ApplicationUserRole>()
|
|
||||||
.WithOne()
|
|
||||||
.HasForeignKey(ur => ur.UserId).IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationUser>().ToTable("ApplicationUser")
|
|
||||||
.HasKey(x => x.Id);
|
|
||||||
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRole>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(r => r.Id);
|
|
||||||
b.HasIndex(r => r.NormalizedName).HasDatabaseName("RoleNameIndex").IsUnique();
|
|
||||||
b.ToTable("Roles");
|
|
||||||
b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();
|
|
||||||
|
|
||||||
b.Property(u => u.Name).HasMaxLength(256);
|
|
||||||
b.Property(u => u.NormalizedName).HasMaxLength(256);
|
|
||||||
|
|
||||||
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
|
|
||||||
b.HasMany<ApplicationRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationUserRole>().HasOne<ApplicationRole>(x => x.ApplicationRole);
|
|
||||||
builder.Entity<ApplicationRoleClaim>().HasOne<ApplicationRole>(x => x.ApplicationRole);
|
|
||||||
builder.Entity<ApplicationUserClaim>().HasOne<ApplicationUser>(x => x.ApplicationUser);
|
|
||||||
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRoleClaim>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(rc => rc.Id);
|
|
||||||
b.ToTable("RoleClaims");
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationUserRole>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(r => new {r.UserId, r.RoleId});
|
|
||||||
b.ToTable("UserRoles");
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<User>(b => b.HasOne<ApplicationUser>()
|
|
||||||
.WithMany(x => x.Users)
|
|
||||||
.HasForeignKey(x => x.ApplicationUserId));
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRoleClaim>().ToTable("RoleClaims");
|
|
||||||
builder.Entity<ApplicationUserRole>().ToTable("UserRole");
|
|
||||||
|
|
||||||
|
|
||||||
builder.ConfigureCurrentDbModel();
|
builder.ConfigureCurrentDbModel();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
/// <inheritdoc />
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using BlueWest.Data;
|
using BlueWest.Data;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using BlueWest.WebApi.Context.Users;
|
using BlueWest.WebApi.Context.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -11,9 +12,7 @@ namespace BlueWest.WebApi.EF.Model
|
||||||
{
|
{
|
||||||
#region Initialization
|
#region Initialization
|
||||||
|
|
||||||
static ModelBuilderExtensions()
|
static ModelBuilderExtensions() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setup the database model
|
/// Setup the database model
|
||||||
|
@ -24,11 +23,105 @@ namespace BlueWest.WebApi.EF.Model
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.ConfigureDatabaseKeys()
|
.ConfigureDatabaseKeys()
|
||||||
.CurrencyModel()
|
.CurrencyModel()
|
||||||
.ConfigureUserModel();
|
.ConfigureUserModel()
|
||||||
|
.ConfigureAppContextModel();
|
||||||
|
|
||||||
//.ConfigureIdentityModel();
|
//.ConfigureIdentityModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Application Users
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure App context model
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelBuilder"></param>
|
||||||
|
private static void ConfigureAppContextModel(this ModelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Entity<ApplicationUserRole>().ToTable("UserRoles");
|
||||||
|
builder.Entity<ApplicationUser>(b =>
|
||||||
|
{
|
||||||
|
b.HasMany<ApplicationUserRole>()
|
||||||
|
.WithOne(b => b.User)
|
||||||
|
.HasForeignKey(ur => ur.UserId).IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
builder.Entity<ApplicationUser>().ToTable("ApplicationUser")
|
||||||
|
.HasKey(x => x.Id);
|
||||||
|
|
||||||
|
|
||||||
|
builder.Entity<ApplicationRole>(b =>
|
||||||
|
{
|
||||||
|
b.HasKey(r => r.Id);
|
||||||
|
b.HasIndex(r => r.NormalizedName).HasDatabaseName("RoleNameIndex").IsUnique();
|
||||||
|
b.ToTable("Roles");
|
||||||
|
b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property(u => u.Name).HasMaxLength(256);
|
||||||
|
b.Property(u => u.NormalizedName).HasMaxLength(256);
|
||||||
|
|
||||||
|
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
|
||||||
|
b.HasMany<ApplicationRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<ApplicationUserRole>().HasOne(x => x.ApplicationRole);
|
||||||
|
builder.Entity<ApplicationRoleClaim>().HasOne<ApplicationRole>(x => x.ApplicationRole);
|
||||||
|
builder.Entity<ApplicationUserClaim>().HasOne<ApplicationUser>(x => x.ApplicationUser);
|
||||||
|
|
||||||
|
|
||||||
|
builder.Entity<ApplicationRoleClaim>(b =>
|
||||||
|
{
|
||||||
|
b.HasKey(rc => rc.Id);
|
||||||
|
b.ToTable("RoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<ApplicationUserRole>(b =>
|
||||||
|
{
|
||||||
|
b.HasKey(r => new {r.UserId, r.RoleId});
|
||||||
|
b.ToTable("UserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<ApplicationRoleClaim>().ToTable("RoleClaims");
|
||||||
|
builder.Entity<ApplicationUserRole>().ToTable("UserRole");
|
||||||
|
|
||||||
|
// Session Token
|
||||||
|
builder.Entity<SessionToken>()
|
||||||
|
.HasOne(b => b.User)
|
||||||
|
.WithMany(x => x.SessionToken)
|
||||||
|
.HasForeignKey(x => x.UserId);
|
||||||
|
|
||||||
|
// Session Token Primary Key
|
||||||
|
builder.Entity<SessionToken>(b =>
|
||||||
|
b.HasKey(x => x.Id));
|
||||||
|
builder.Entity<SessionToken>(b =>
|
||||||
|
b.Property(x => x.Id).ValueGeneratedOnAdd());
|
||||||
|
|
||||||
|
// Session Data
|
||||||
|
builder.Entity<SessionData>()
|
||||||
|
.HasOne(b => b.User)
|
||||||
|
.WithMany(x => x.SessionDatas)
|
||||||
|
.HasForeignKey(x => x.UserId);
|
||||||
|
|
||||||
|
// Session Data
|
||||||
|
builder.Entity<SessionData>()
|
||||||
|
.HasOne(b => b.SessionToken)
|
||||||
|
.WithOne(x => x.SessionData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Session Data Primary Key
|
||||||
|
builder.Entity<SessionData>(b =>
|
||||||
|
b.HasKey(x => x.Id));
|
||||||
|
builder.Entity<SessionData>(b =>
|
||||||
|
b.Property(x => x.Id).ValueGeneratedOnAdd());
|
||||||
|
|
||||||
|
|
||||||
|
//.ConfigureIdentityModel();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DatabasePK
|
#region DatabasePK
|
||||||
|
@ -121,48 +214,11 @@ namespace BlueWest.WebApi.EF.Model
|
||||||
.WithMany(ft => ft.FinanceTransactions)
|
.WithMany(ft => ft.FinanceTransactions)
|
||||||
.HasForeignKey(x => x.UserId));
|
.HasForeignKey(x => x.UserId));
|
||||||
|
|
||||||
modelBuilder.Entity<User>(b => b.HasOne<ApplicationUser>()
|
|
||||||
.WithMany(x => x.Users)
|
|
||||||
.HasForeignKey(x => x.ApplicationUserId));
|
|
||||||
|
|
||||||
return modelBuilder;
|
return modelBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static void ConfigureIdentityModel(this ModelBuilder builder)
|
|
||||||
{
|
|
||||||
builder.Entity<ApplicationUser>(b =>
|
|
||||||
{
|
|
||||||
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRole>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(r => r.Id);
|
|
||||||
b.HasIndex(r => r.NormalizedName).HasDatabaseName("RoleNameIndex").IsUnique();
|
|
||||||
b.ToTable("Roles");
|
|
||||||
b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();
|
|
||||||
|
|
||||||
b.Property(u => u.Name).HasMaxLength(256);
|
|
||||||
b.Property(u => u.NormalizedName).HasMaxLength(256);
|
|
||||||
|
|
||||||
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
|
|
||||||
b.HasMany<ApplicationRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRoleClaim>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(rc => rc.Id);
|
|
||||||
b.ToTable("RoleClaims");
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationUserRole>(b =>
|
|
||||||
{
|
|
||||||
b.HasKey(r => new { r.UserId, r.RoleId });
|
|
||||||
b.ToTable("UserRoles");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using BlueWest.Data.Application;
|
||||||
|
using BlueWest.WebApi.EF.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.InMemory;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Context
|
||||||
|
{
|
||||||
|
|
||||||
|
public class SessionDbContext : DbContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CountryDbContext Constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
|
||||||
|
public SessionDbContext(DbContextOptions<SessionDbContext> options) : base(options)
|
||||||
|
{
|
||||||
|
Database.EnsureCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
modelBuilder.ConfigureCurrentDbModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<SessionToken> SessionTokens { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("application")]
|
||||||
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
|
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||||
|
[EnableCors(Constants.CorsPolicyName)]
|
||||||
|
public class ApplicationController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
|
public ContentResult GetTimeTicks() => Content(
|
||||||
|
DateTime.Now.Ticks.ToString());
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using BlueWest.Data;
|
using BlueWest.Data;
|
||||||
using BlueWest.WebApi.Context;
|
using BlueWest.WebApi.Context;
|
||||||
|
using BlueWest.WebApi.Context.Users;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Controllers
|
namespace BlueWest.WebApi.Controllers
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("application/users")]
|
[Route("application/users")]
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
|
@ -19,6 +21,7 @@ namespace BlueWest.WebApi.Controllers
|
||||||
{
|
{
|
||||||
private readonly ApplicationUserDbContext _dbContext;
|
private readonly ApplicationUserDbContext _dbContext;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public ApplicationUserController(ApplicationUserDbContext context)
|
public ApplicationUserController(ApplicationUserDbContext context)
|
||||||
{
|
{
|
||||||
_dbContext = context;
|
_dbContext = context;
|
||||||
|
@ -54,16 +57,15 @@ namespace BlueWest.WebApi.Controllers
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
[HttpPut("{UserCode}")]
|
[HttpPut("{UserCode}")]
|
||||||
public ActionResult UpdateApplicationUser(int UserCode, UserUnique UserToUpdate)
|
public ActionResult UpdateApplicationUser(string applicationUserId, ApplicationUserUnique UserToUpdate)
|
||||||
{
|
{
|
||||||
//var (success, User) = _dbContext.UpdateUser(UserToUpdate, UserCode);
|
var (success, updatedUser) = _dbContext.UpdateApplicationUser(UserToUpdate, applicationUserId);
|
||||||
|
|
||||||
/*
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
return Ok(User);
|
return Ok(updatedUser);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return new NotFoundResult();
|
return new NotFoundResult();
|
||||||
}
|
}
|
||||||
|
@ -124,8 +126,14 @@ namespace BlueWest.WebApi.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Application Constants
|
||||||
|
/// </summary>
|
||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Policy Name
|
||||||
|
/// </summary>
|
||||||
public const string CorsPolicyName = "_myAllowSpecificOrigins";
|
public const string CorsPolicyName = "_myAllowSpecificOrigins";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
using System;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BlueWest.Cryptography;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using BlueWest.WebApi.Context.Users;
|
using BlueWest.WebApi.Context.Users;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
@ -14,25 +17,28 @@ namespace BlueWest.WebApi.Controllers;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Auth controller
|
/// Auth controller
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("api/[controller]")]
|
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
|
||||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[EnableCors(Constants.CorsPolicyName)]
|
[Route("api/[controller]")]
|
||||||
public class AuthController : Controller
|
|
||||||
|
[Authorize(Policy = "ApiUser")]
|
||||||
|
|
||||||
|
/*[EnableCors(Constants.CorsPolicyName)]*/
|
||||||
|
public class AuthController : Controller
|
||||||
{
|
{
|
||||||
private readonly IAuthManager _authManager;
|
private readonly IAuthManager _authManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
|
private readonly ISessionManager _sessionManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="authManager"></param>
|
/// <param name="authManager"></param>
|
||||||
/// <param name="userManager"></param>
|
/// <param name="userManager"></param>
|
||||||
public AuthController( IAuthManager authManager, IUserManager userManager)
|
public AuthController( IAuthManager authManager, IUserManager userManager, ISessionManager sessionManager)
|
||||||
{
|
{
|
||||||
_authManager = authManager;
|
_authManager = authManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
_sessionManager = sessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,25 +55,60 @@ public class AuthController : Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a bearer token
|
/// Gets a bearer token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="loginViewModel"></param>
|
/// <param name="loginViewModel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpPost("login")]
|
[HttpPost("token")]
|
||||||
public async Task<ActionResult<IdentityResult>> GetTokenAsync(LoginViewModel loginViewModel)
|
public async Task<ActionResult<IdentityResult>> GetTokenAsync(LoginRequest loginViewModel)
|
||||||
{
|
{
|
||||||
var loginResultSucceded = await _authManager.GetToken(loginViewModel);
|
var (success, sessionToken, token) = await _authManager.GetToken(loginViewModel);
|
||||||
|
|
||||||
if (loginResultSucceded != null)
|
if (success)
|
||||||
{
|
{
|
||||||
return Ok(loginResultSucceded);
|
return Ok(new {sessionToken, token});
|
||||||
|
|
||||||
}
|
}
|
||||||
return Problem();
|
return Problem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if user is logged in
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("isLoggedIn")]
|
||||||
|
|
||||||
|
public ActionResult<bool> IsLoggedIn()
|
||||||
|
{
|
||||||
|
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
if (identity.IsAuthenticated)
|
||||||
|
{
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the session is authorized
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hash"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("isAuthorized")]
|
||||||
|
|
||||||
|
public ActionResult IsAuthorized(string hash)
|
||||||
|
{
|
||||||
|
var isAuthorized = _sessionManager.IsAuthorized(hash);
|
||||||
|
|
||||||
|
return Ok(isAuthorized ? new {authenticated = true} : new {authenticated = false});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Do Cookie based login.
|
/// Do Cookie based login.
|
||||||
|
@ -75,23 +116,26 @@ public class AuthController : Controller
|
||||||
/// <param name="loginDto"></param>
|
/// <param name="loginDto"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpPost("logincookie")]
|
[HttpPost("login")]
|
||||||
public async Task<ActionResult<IdentityResult>> DoLoginAsync(LoginViewModel loginDto)
|
public async Task<ActionResult> DoLoginAsync(LoginRequest loginDto)
|
||||||
{
|
{
|
||||||
var user = await _userManager.FindByEmailAsync(loginDto.Email);
|
var (success, identity, sessionToken) = await _authManager.DoLogin(loginDto);
|
||||||
|
|
||||||
if (user != null)
|
if (success)
|
||||||
{
|
{
|
||||||
if(await _userManager.CheckPasswordAsync(user, loginDto.Password))
|
await HttpContext.SignInAsync(
|
||||||
{
|
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||||
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
new ClaimsPrincipal(identity),
|
||||||
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
new AuthenticationProperties
|
||||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
|
{
|
||||||
return Ok(new {authenticated = true});
|
IsPersistent = true,
|
||||||
}
|
ExpiresUtc = DateTime.UtcNow.AddDays(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ok(new {authenticated = true, sessionToken});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(new {authenticated = false});
|
return new ForbidResult(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -101,10 +145,9 @@ public class AuthController : Controller
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpPost("logout")]
|
[HttpPost("logout")]
|
||||||
public async Task<ActionResult<IdentityResult>> DoLogoutAsync(LoginViewModel loginDto)
|
public async Task DoLogoutAsync()
|
||||||
{
|
{
|
||||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
return Json(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,8 +18,7 @@ namespace BlueWest.WebApi.Controllers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
[Authorize(Policy = "ApiUser")]
|
||||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
|
||||||
[EnableCors(Constants.CorsPolicyName)]
|
[EnableCors(Constants.CorsPolicyName)]
|
||||||
// [Authorize(Roles = "Administrator")]
|
// [Authorize(Roles = "Administrator")]
|
||||||
public class CountryController : ControllerBase
|
public class CountryController : ControllerBase
|
||||||
|
|
|
@ -6,6 +6,7 @@ using BlueWest.WebApi.EF;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
@ -18,6 +19,8 @@ namespace BlueWest.WebApi.Controllers
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||||
|
[EnableCors(Constants.CorsPolicyName)]
|
||||||
|
|
||||||
// [Authorize(Roles = "Administrator")]
|
// [Authorize(Roles = "Administrator")]
|
||||||
public partial class CurrencyController : ControllerBase
|
public partial class CurrencyController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@ using BlueWest.WebApi.EF;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
@ -16,7 +17,9 @@ namespace BlueWest.WebApi.Controllers;
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||||
[Authorize(Roles = "Administrator")]
|
//[Authorize(Roles = "Administrator")]
|
||||||
|
[EnableCors(Constants.CorsPolicyName)]
|
||||||
|
|
||||||
public class FinanceController : ControllerBase
|
public class FinanceController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly FinanceDbContext _dbContext;
|
private readonly FinanceDbContext _dbContext;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using BlueWest.WebApi.EF;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
@ -19,8 +20,9 @@ namespace BlueWest.WebApi.Controllers
|
||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||||
[Authorize(Roles = "Administrator")]
|
//[Authorize(Roles = "Administrator")]
|
||||||
|
[EnableCors(Constants.CorsPolicyName)]
|
||||||
|
|
||||||
public class UserController : ControllerBase
|
public class UserController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ COPY ["BlueWest/BlueWest.csproj", "BlueWest/"]
|
||||||
RUN dotnet restore "BlueWest/BlueWest.csproj"
|
RUN dotnet restore "BlueWest/BlueWest.csproj"
|
||||||
|
|
||||||
|
|
||||||
COPY ["BlueWest.Data.Geography/BlueWest.Data.Geography.csproj", "BlueWest.Data.Geography/"]
|
COPY ["BlueWest.Data.Application/BlueWest.Data.Application.csproj", "BlueWest.Data.Application/"]
|
||||||
RUN dotnet restore "BlueWest.Data.Geography/BlueWest.Data.Geography.csproj"
|
RUN dotnet restore "BlueWest.Data.Application/BlueWest.Data.Application.csproj"
|
||||||
|
|
||||||
|
|
||||||
COPY ["BlueWest.Api/BlueWest.Api.csproj", "BlueWest.Api/"]
|
COPY ["BlueWest.Api/BlueWest.Api.csproj", "BlueWest.Api/"]
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi;
|
||||||
|
|
||||||
|
public class GreeterService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Redis.OM;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi
|
||||||
|
{
|
||||||
|
public class IndexCreationDevice : IHostedService
|
||||||
|
{
|
||||||
|
private readonly RedisConnectionProvider _provider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index Creation Device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="provider"></param>
|
||||||
|
public IndexCreationDevice(RedisConnectionProvider provider)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await _provider.Connection.CreateIndexAsync(typeof(SessionToken)); }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using Grpc.Core.Interceptors;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Interceptors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Server Logger Interceptor
|
||||||
|
/// </summary>
|
||||||
|
public class ServerLoggerInterceptor : Interceptor
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using BlueWest.Data.Application;
|
||||||
|
using BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi
|
||||||
|
{
|
||||||
|
public interface ISessionManager
|
||||||
|
{
|
||||||
|
bool IsAuthorized(string tokenHash);
|
||||||
|
|
||||||
|
SessionToken GetSessionToken(string hash, ApplicationUser applicationUser);
|
||||||
|
|
||||||
|
SessionToken GetSessionToken(LoginRequest loginRequest, ApplicationUser user);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using BlueWest.Cryptography;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
|
using BlueWest.WebApi.Context;
|
||||||
|
using BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi
|
||||||
|
{
|
||||||
|
internal class SessionManager : ISessionManager
|
||||||
|
{
|
||||||
|
private readonly SessionDbContext _dbContex;
|
||||||
|
private readonly IHasher _hasher;
|
||||||
|
|
||||||
|
public SessionManager(SessionDbContext sessionDbContext, IHasher hasher)
|
||||||
|
{
|
||||||
|
_dbContex = sessionDbContext;
|
||||||
|
_hasher = hasher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if token is authorized
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hash"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool IsAuthorized(string hash)
|
||||||
|
{
|
||||||
|
var sessionToken = _dbContex.SessionTokens.FirstOrDefault(x => x.Token == hash);
|
||||||
|
|
||||||
|
if (sessionToken is not {IsValid: true}) return false;
|
||||||
|
|
||||||
|
var expirationDate = sessionToken.CreatedDate.Add(sessionToken.ValidFor);
|
||||||
|
|
||||||
|
if (expirationDate >= DateTime.Now)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a new or existing session token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hash"></param>
|
||||||
|
/// <param name="applicationUser"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public SessionToken GetSessionToken(string hash, ApplicationUser applicationUser)
|
||||||
|
{
|
||||||
|
var sessionToken = _dbContex.SessionTokens.FirstOrDefault(x => x.Token == hash);
|
||||||
|
|
||||||
|
if (sessionToken == null)
|
||||||
|
{
|
||||||
|
// Create token;
|
||||||
|
var newToken = new SessionToken
|
||||||
|
{
|
||||||
|
Token = hash,
|
||||||
|
CreatedDate = DateTime.Now,
|
||||||
|
ValidFor = TimeSpan.FromDays(1),
|
||||||
|
UserId = applicationUser.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
_dbContex.SessionTokens.Add(newToken);
|
||||||
|
var result = _dbContex.SaveChanges() >= 0;
|
||||||
|
|
||||||
|
return !result ? null : newToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expirationDate = sessionToken.CreatedDate.Add(sessionToken.ValidFor);
|
||||||
|
|
||||||
|
if (expirationDate >= DateTime.Now)
|
||||||
|
{
|
||||||
|
return sessionToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a session token for the user following a login request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loginRequest"></param>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public SessionToken GetSessionToken(LoginRequest loginRequest, ApplicationUser user)
|
||||||
|
{
|
||||||
|
var content = $"{loginRequest.Uuid}|{user.Email}";
|
||||||
|
var hash = _hasher.CreateHash(content, BaseCryptoItem.HashAlgorithm.SHA2_512);
|
||||||
|
var sessionToken = GetSessionToken(hash, user);
|
||||||
|
return sessionToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,12 +7,11 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using BlueWest.Tools;
|
using BlueWest.Tools;
|
||||||
using BlueWest.WebApi.Context.Users;
|
using BlueWest.WebApi.Interceptors;
|
||||||
using BlueWest.WebApi.Interfaces;
|
using BlueWest.WebApi.Interfaces;
|
||||||
using BlueWest.WebApi.Tools;
|
using BlueWest.WebApi.Tools;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.FileProviders;
|
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
namespace BlueWest.WebApi
|
namespace BlueWest.WebApi
|
||||||
|
@ -24,6 +23,7 @@ namespace BlueWest.WebApi
|
||||||
{
|
{
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly IWebHostEnvironment _environment;
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
|
||||||
private readonly string MyAllowSpecificOrigins = Constants.CorsPolicyName;
|
private readonly string MyAllowSpecificOrigins = Constants.CorsPolicyName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -47,7 +47,7 @@ namespace BlueWest.WebApi
|
||||||
options.AddPolicy(name: MyAllowSpecificOrigins,
|
options.AddPolicy(name: MyAllowSpecificOrigins,
|
||||||
builder =>
|
builder =>
|
||||||
{
|
{
|
||||||
builder.WithOrigins("http://127.0.0.1:5173", "http://localhost:5173", "http://127.0.0.1:5173")
|
builder.WithOrigins("http://localhost:5173/", "http://localhost:5173", "http://127.0.0.1:5173", "localhost:5173")
|
||||||
.AllowAnyMethod()
|
.AllowAnyMethod()
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.AllowCredentials();
|
.AllowCredentials();
|
||||||
|
@ -55,9 +55,27 @@ namespace BlueWest.WebApi
|
||||||
});
|
});
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddControllers()
|
.AddResponseCaching()
|
||||||
|
.AddControllers(options =>
|
||||||
|
{
|
||||||
|
options.CacheProfiles.Add("Default30",
|
||||||
|
new CacheProfile()
|
||||||
|
{
|
||||||
|
Duration = 30
|
||||||
|
});
|
||||||
|
})
|
||||||
.AddJsonOptions(options => options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve);
|
.AddJsonOptions(options => options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve);
|
||||||
|
|
||||||
|
services.AddLogging(builder =>
|
||||||
|
{
|
||||||
|
builder.AddSimpleConsole();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSession(options =>
|
||||||
|
{
|
||||||
|
options.Cookie.Domain = "http://localhost:5173";
|
||||||
|
options.Cookie.HttpOnly = true;
|
||||||
|
});
|
||||||
services
|
services
|
||||||
.AddSwaggerGen(options =>
|
.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
|
@ -101,7 +119,14 @@ namespace BlueWest.WebApi
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
services.AddGrpc(options =>
|
||||||
|
{
|
||||||
|
options.Interceptors.Add<ServerLoggerInterceptor>();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSingleton<ServerLoggerInterceptor>();
|
||||||
/*
|
/*
|
||||||
services.AddSingleton<IFileProvider>(
|
services.AddSingleton<IFileProvider>(
|
||||||
new PhysicalFileProvider(
|
new PhysicalFileProvider(
|
||||||
|
@ -119,10 +144,12 @@ namespace BlueWest.WebApi
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddSingleton<EventManager>();
|
.AddSingleton<EventManager>();
|
||||||
|
|
||||||
|
|
||||||
services.AddAuthServerServices(MyAllowSpecificOrigins, _configuration, _environment);
|
services.AddAuthServerServices( _configuration, _environment);
|
||||||
services.AddScoped<ExchangeInterface>();
|
services.AddScoped<ExchangeInterface>();
|
||||||
|
|
||||||
|
|
||||||
switch (allowedDatabase)
|
switch (allowedDatabase)
|
||||||
{
|
{
|
||||||
case "mysql":
|
case "mysql":
|
||||||
|
@ -138,10 +165,6 @@ namespace BlueWest.WebApi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// services.AddGrpc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,19 +179,17 @@ namespace BlueWest.WebApi
|
||||||
|
|
||||||
//app.UseStaticFiles();
|
//app.UseStaticFiles();
|
||||||
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
|
|
||||||
app.UseSwaggerUI(c =>
|
app.UseSwaggerUI(c =>
|
||||||
{
|
{
|
||||||
c.RoutePrefix = "swagger";
|
c.RoutePrefix = "swagger";
|
||||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.Api v1");
|
c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.Api v1");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
//app.UseHttpsRedirection();
|
//app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseCors(MyAllowSpecificOrigins);
|
app.UseCors(MyAllowSpecificOrigins);
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -80,7 +81,9 @@ namespace BlueWest.WebApi
|
||||||
.AddDbContextPool<CountryDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
.AddDbContextPool<CountryDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
||||||
.AddDbContextPool<FinanceDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
.AddDbContextPool<FinanceDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
||||||
.AddDbContextPool<CompanyDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
.AddDbContextPool<CompanyDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
||||||
.AddDbContextPool<ApplicationUserDbContext>(options => options.GetMySqlSettings(configuration, environment));
|
.AddDbContextPool<ApplicationUserDbContext>(options =>
|
||||||
|
options.GetMySqlSettings(configuration, environment))
|
||||||
|
.AddDbContextPool<SessionDbContext>(options => options.UseInMemoryDatabase("_s"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -100,27 +103,24 @@ namespace BlueWest.WebApi
|
||||||
.AddDbContextPool<CountryDbContext>(options => options.UseSqlite(sqliteConString))
|
.AddDbContextPool<CountryDbContext>(options => options.UseSqlite(sqliteConString))
|
||||||
.AddDbContextPool<FinanceDbContext>(options => options.UseSqlite(sqliteConString))
|
.AddDbContextPool<FinanceDbContext>(options => options.UseSqlite(sqliteConString))
|
||||||
.AddDbContextPool<CompanyDbContext>(options => options.UseSqlite(sqliteConString))
|
.AddDbContextPool<CompanyDbContext>(options => options.UseSqlite(sqliteConString))
|
||||||
.AddDbContextPool<ApplicationUserDbContext>(options => options.UseSqlite(sqliteConString));
|
.AddDbContextPool<ApplicationUserDbContext>(options => options.UseSqlite(sqliteConString))
|
||||||
|
.AddDbContextPool<SessionDbContext>(options => options.UseInMemoryDatabase("_s"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, string origins, IConfiguration configuration , IWebHostEnvironment environment)
|
internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, IConfiguration configuration , IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
|
|
||||||
services.AddScoped<IJwtTokenHandler, JwtTokenHandler>();
|
services.AddScoped<IJwtTokenHandler, JwtTokenHandler>()
|
||||||
services.AddScoped<IJwtFactory, JwtFactory>();
|
.AddScoped<IJwtFactory, JwtFactory>()
|
||||||
|
.AddSingleton<IndexCreationDevice>()
|
||||||
|
.AddScoped<ISessionManager, SessionManager>()
|
||||||
services
|
.AddScoped<UserRepository>()
|
||||||
.AddScoped< UserRepository>()
|
|
||||||
.AddScoped<IUserManager, ApplicationUserManager>()
|
.AddScoped<IUserManager, ApplicationUserManager>()
|
||||||
.AddScoped<IAuthManager, AuthManager>()
|
.AddScoped<IAuthManager, AuthManager>()
|
||||||
|
|
||||||
.AddScoped<IHasher, Hasher>();
|
.AddScoped<IHasher, Hasher>();
|
||||||
|
|
||||||
services
|
|
||||||
.AddIdentityCore<ApplicationUser>(opt => { opt.User.RequireUniqueEmail = true; })
|
|
||||||
.AddUserManager<ApplicationUserManager>()
|
|
||||||
.AddUserStore<UserRepository>();
|
|
||||||
// Database Context and Swagger
|
// Database Context and Swagger
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,6 +162,7 @@ namespace BlueWest.WebApi
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
services.AddAuthentication(options =>
|
||||||
{
|
{
|
||||||
|
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
@ -170,6 +171,9 @@ namespace BlueWest.WebApi
|
||||||
})
|
})
|
||||||
.AddCookie(options =>
|
.AddCookie(options =>
|
||||||
{
|
{
|
||||||
|
options.Cookie.SameSite = SameSiteMode.Lax;
|
||||||
|
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
||||||
|
options.Cookie.MaxAge = TimeSpan.FromDays(1);
|
||||||
options.LoginPath = "/api/auth/logincookie";
|
options.LoginPath = "/api/auth/logincookie";
|
||||||
options.LogoutPath = "/api/auth/logout";
|
options.LogoutPath = "/api/auth/logout";
|
||||||
})
|
})
|
||||||
|
@ -206,13 +210,17 @@ namespace BlueWest.WebApi
|
||||||
// add identity
|
// add identity
|
||||||
var identityBuilder = services.AddIdentityCore<ApplicationUser>(o =>
|
var identityBuilder = services.AddIdentityCore<ApplicationUser>(o =>
|
||||||
{
|
{
|
||||||
|
o.User.RequireUniqueEmail = true;
|
||||||
|
|
||||||
// configure identity options
|
// configure identity options
|
||||||
o.Password.RequireDigit = false;
|
o.Password.RequireDigit = false;
|
||||||
o.Password.RequireLowercase = false;
|
o.Password.RequireLowercase = false;
|
||||||
o.Password.RequireUppercase = false;
|
o.Password.RequireUppercase = false;
|
||||||
o.Password.RequireNonAlphanumeric = false;
|
o.Password.RequireNonAlphanumeric = false;
|
||||||
o.Password.RequiredLength = 6;
|
o.Password.RequiredLength = 6;
|
||||||
});
|
})
|
||||||
|
.AddUserManager<ApplicationUserManager>()
|
||||||
|
.AddUserStore<UserRepository>();
|
||||||
|
|
||||||
identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services);
|
identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services);
|
||||||
identityBuilder
|
identityBuilder
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BlueWest.Cryptography;
|
using BlueWest.Cryptography;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
@ -16,12 +17,16 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
||||||
{
|
{
|
||||||
private readonly IHasher _hasher;
|
private readonly IHasher _hasher;
|
||||||
private readonly UserRepository _usersRepo;
|
private readonly UserRepository _usersRepo;
|
||||||
public ApplicationUserManager(UserRepository store, IOptions<IdentityOptions> optionsAccessor,
|
public ApplicationUserManager(
|
||||||
IHasher passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
|
UserRepository store,
|
||||||
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
|
IOptions<IdentityOptions> optionsAccessor,
|
||||||
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store,
|
IHasher passwordHasher,
|
||||||
optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services,
|
IEnumerable<IUserValidator<ApplicationUser>> userValidators,
|
||||||
logger)
|
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators,
|
||||||
|
ILookupNormalizer keyNormalizer,
|
||||||
|
IdentityErrorDescriber errors,
|
||||||
|
IServiceProvider services,
|
||||||
|
ILogger<UserManager<ApplicationUser>> logger) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
|
||||||
{
|
{
|
||||||
_hasher = passwordHasher;
|
_hasher = passwordHasher;
|
||||||
_usersRepo = store;
|
_usersRepo = store;
|
||||||
|
@ -49,6 +54,7 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override async Task<PasswordVerificationResult> VerifyPasswordAsync(IUserPasswordStore<ApplicationUser> store, ApplicationUser user, string password)
|
protected override async Task<PasswordVerificationResult> VerifyPasswordAsync(IUserPasswordStore<ApplicationUser> store, ApplicationUser user, string password)
|
||||||
{
|
{
|
||||||
string existingHash;
|
string existingHash;
|
||||||
|
@ -89,7 +95,11 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
||||||
Logger.LogWarning(2, "Change password failed for user {userId}.", await GetUserIdAsync(user));
|
Logger.LogWarning(2, "Change password failed for user {userId}.", await GetUserIdAsync(user));
|
||||||
return IdentityResult.Failed(ErrorDescriber.PasswordMismatch());
|
return IdentityResult.Failed(ErrorDescriber.PasswordMismatch());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task<IdentityResult> SetAuthenticationTokenAsync(ApplicationUser user, string loginProvider, string tokenName, string tokenValue)
|
||||||
|
{
|
||||||
|
return base.SetAuthenticationTokenAsync(user, loginProvider, tokenName, tokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
private IUserPasswordStore<ApplicationUser> GetPasswordStore()
|
private IUserPasswordStore<ApplicationUser> GetPasswordStore()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Security.Claims;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BlueWest.Cryptography;
|
using BlueWest.Cryptography;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users;
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
internal class AuthManager : IAuthManager
|
internal class AuthManager : IAuthManager
|
||||||
{
|
{
|
||||||
private readonly IUserManager _userManager;
|
private readonly ApplicationUserManager _userManager;
|
||||||
private readonly UserRepository _usersRepo;
|
private readonly UserRepository _usersRepo;
|
||||||
|
private readonly ISessionManager _sessionManager;
|
||||||
private readonly IHasher _hasher;
|
private readonly IHasher _hasher;
|
||||||
private readonly IJwtFactory _jwtFactory;
|
private readonly IJwtFactory _jwtFactory;
|
||||||
|
|
||||||
|
@ -19,51 +25,79 @@ internal class AuthManager : IAuthManager
|
||||||
/// <param name="hasher"></param>
|
/// <param name="hasher"></param>
|
||||||
/// <param name="usersRepo"></param>
|
/// <param name="usersRepo"></param>
|
||||||
/// <param name="jwtFactory"></param>
|
/// <param name="jwtFactory"></param>
|
||||||
public AuthManager(IUserManager userManager, IHasher hasher, UserRepository usersRepo, IJwtFactory jwtFactory)
|
public AuthManager(
|
||||||
|
ApplicationUserManager userManager,
|
||||||
|
IHasher hasher,
|
||||||
|
UserRepository usersRepo,
|
||||||
|
ISessionManager sessionManager,
|
||||||
|
IJwtFactory jwtFactory)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_hasher = hasher;
|
_hasher = hasher;
|
||||||
_usersRepo = usersRepo;
|
_usersRepo = usersRepo;
|
||||||
_jwtFactory = jwtFactory;
|
_jwtFactory = jwtFactory;
|
||||||
|
_sessionManager = sessionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(bool, ClaimsIdentity, SessionTokenUnique)> DoLogin(LoginRequest loginRequest)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
if(await _userManager.CheckPasswordAsync(user, loginRequest.Password))
|
||||||
|
{
|
||||||
|
// Identity
|
||||||
|
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
||||||
|
|
||||||
|
// Session
|
||||||
|
var sessionToken = _sessionManager.GetSessionToken(loginRequest, user);
|
||||||
|
var sessionResponse = new SessionTokenUnique(sessionToken);
|
||||||
|
return (true, identity, sessionResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<AccessToken> GetToken(LoginViewModel loginViewModel)
|
public async Task<(bool, SessionTokenUnique, AccessToken)> GetToken(LoginRequest loginRequest)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(loginViewModel.Email) && !string.IsNullOrEmpty(loginViewModel.Password))
|
if (!string.IsNullOrEmpty(loginRequest.Email) && !string.IsNullOrEmpty(loginRequest.Password))
|
||||||
{
|
{
|
||||||
var user = await _userManager.FindByEmailAsync(loginViewModel.Email);
|
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
if (await VerifyLoginAsync(loginViewModel.Email,loginViewModel.Password))
|
if (await VerifyLoginByEmailAsync(loginRequest.Email,loginRequest.Password))
|
||||||
{
|
{
|
||||||
// Todo generate refresh token
|
|
||||||
// Todo Add refresh token
|
|
||||||
await _usersRepo.UpdateAsync(user, CancellationToken.None);
|
await _usersRepo.UpdateAsync(user, CancellationToken.None);
|
||||||
var token = await _jwtFactory.GenerateEncodedToken(user.Id.ToString(), user.UserName);
|
// Session
|
||||||
// await _userManager.SetAuthenticationTokenAsync(user, "Income", "ApiUser", token.Token);
|
var sessionToken = _sessionManager.GetSessionToken(loginRequest, user);
|
||||||
|
var sessionResponse = new SessionTokenUnique(sessionToken);
|
||||||
|
|
||||||
|
var token = await _jwtFactory.GenerateEncodedToken(user.Id, user.UserName);
|
||||||
|
var completed = await _userManager.SetAuthenticationTokenAsync(user, "ApiUser", "ApiUser", token.Token);
|
||||||
|
|
||||||
return token;
|
return (completed == IdentityResult.Success, sessionResponse, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return (false, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> VerifyLoginAsync(string email, string password)
|
public async Task<bool> VerifyLoginByEmailAsync(string email, string password)
|
||||||
{
|
{
|
||||||
var user = await _userManager.FindByEmailAsync(email);
|
var user = await _userManager.FindByEmailAsync(email);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return false; // return error user doesn't exist
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _userManager.CheckPasswordAsync(user, password);
|
return await _userManager.CheckPasswordAsync(user, password);
|
||||||
|
|
||||||
// return await GenerateAuthenticationResultForUserAsync(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegisterViewModel FromSignupToUser(RegisterViewModel signupDto)
|
private RegisterViewModel FromSignupToUser(RegisterViewModel signupDto)
|
||||||
|
@ -71,8 +105,6 @@ internal class AuthManager : IAuthManager
|
||||||
var pwd = signupDto.Password;
|
var pwd = signupDto.Password;
|
||||||
var hash = _hasher.CreateHash(pwd, BaseCryptoItem.HashAlgorithm.SHA3_512);
|
var hash = _hasher.CreateHash(pwd, BaseCryptoItem.HashAlgorithm.SHA3_512);
|
||||||
signupDto.Password = hash;
|
signupDto.Password = hash;
|
||||||
signupDto.ConfirmPassword = hash;
|
|
||||||
|
|
||||||
return signupDto;
|
return signupDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace BlueWest.Cryptography
|
||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
/// <param name="algorithm"></param>
|
/// <param name="algorithm"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string CreateHash(string text, BaseCryptoItem.HashAlgorithm algorithm)
|
public string CreateHash(string text, HashAlgorithm algorithm)
|
||||||
{
|
{
|
||||||
var salt = CreateRandomString(SaltLength);
|
var salt = CreateRandomString(SaltLength);
|
||||||
return CreateHash(text, salt, algorithm, true);
|
return CreateHash(text, salt, algorithm, true);
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace BlueWest.Cryptography
|
||||||
|
{
|
||||||
|
public interface ISessionHasher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a token for the current session
|
||||||
|
/// </summary>
|
||||||
|
void GenerateSessionToken();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ internal class JwtFactory : IJwtFactory
|
||||||
{
|
{
|
||||||
new Claim(JwtRegisteredClaimNames.Sub, userName),
|
new Claim(JwtRegisteredClaimNames.Sub, userName),
|
||||||
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
|
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Aud, _jwtOptions.Audience),
|
||||||
|
|
||||||
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
|
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
|
||||||
ClaimValueTypes.Integer64),
|
ClaimValueTypes.Integer64),
|
||||||
identity.FindFirst(JwtClaimIdentifiers.Rol),
|
identity.FindFirst(JwtClaimIdentifiers.Rol),
|
|
@ -1,4 +1,7 @@
|
||||||
|
using System;
|
||||||
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users;
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
@ -21,13 +24,20 @@ public interface IAuthManager
|
||||||
/// <param name="email"></param>
|
/// <param name="email"></param>
|
||||||
/// <param name="password"></param>
|
/// <param name="password"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> VerifyLoginAsync(string email, string password);
|
Task<bool> VerifyLoginByEmailAsync(string email, string password);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GetToken
|
/// GetToken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="loginViewModel"></param>
|
/// <param name="loginRequest"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<AccessToken> GetToken(LoginViewModel loginViewModel);
|
Task<(bool, SessionTokenUnique, AccessToken)> GetToken(LoginRequest loginRequest);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does Login
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loginRequest"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<(bool, ClaimsIdentity, SessionTokenUnique)> DoLogin(LoginRequest loginRequest);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users
|
namespace BlueWest.WebApi.Context.Users
|
||||||
|
@ -26,6 +27,9 @@ namespace BlueWest.WebApi.Context.Users
|
||||||
/// <param name="email"></param>
|
/// <param name="email"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ApplicationUser> FindByEmailAsync(string email);
|
Task<ApplicationUser> FindByEmailAsync(string email);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ namespace BlueWest.WebApi.Context.Users
|
||||||
{
|
{
|
||||||
// from: https://github.com/dotnet/aspnetcore/tree/main/src/Identity/samples/IdentitySample.Mvc/Models/AccountViewModels
|
// from: https://github.com/dotnet/aspnetcore/tree/main/src/Identity/samples/IdentitySample.Mvc/Models/AccountViewModels
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Login View Model
|
/// Login Request adata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoginViewModel
|
public class LoginRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Email
|
/// Email
|
||||||
|
@ -21,12 +21,10 @@ namespace BlueWest.WebApi.Context.Users
|
||||||
[Required]
|
[Required]
|
||||||
[DataType(DataType.Password)]
|
[DataType(DataType.Password)]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Uuid { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// RememberMe
|
|
||||||
/// </summary>
|
|
||||||
[Display(Name = "Remember me?")]
|
|
||||||
public bool RememberMe { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,16 @@ public class RegisterViewModel
|
||||||
[Display(Name = "Confirm password")]
|
[Display(Name = "Confirm password")]
|
||||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||||
public string ConfirmPassword { get; set; }
|
public string ConfirmPassword { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ConfirmPassword
|
||||||
|
/// </summary>
|
||||||
|
[DataType(DataType.PhoneNumber)]
|
||||||
|
[Display(Name = "Phone Number")]
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert RegisterViewModel to ApplicationUser
|
/// Convert RegisterViewModel to ApplicationUser
|
||||||
|
@ -46,6 +56,7 @@ public class RegisterViewModel
|
||||||
newUser.Email = Email;
|
newUser.Email = Email;
|
||||||
newUser.PasswordHash = Password;
|
newUser.PasswordHash = Password;
|
||||||
newUser.UserName = Username;
|
newUser.UserName = Username;
|
||||||
|
newUser.PhoneNumber = PhoneNumber;
|
||||||
return newUser;
|
return newUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Role storage management
|
|
||||||
/// </summary>
|
|
||||||
/*public class RoleStore : RoleStore<ApplicationRole>
|
|
||||||
{
|
|
||||||
|
|
||||||
}*/
|
|
|
@ -10,7 +10,12 @@
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DockerMySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;"
|
"DockerMySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;"
|
||||||
},
|
},
|
||||||
|
"REDIS_CONNECTION_STRING": "redis://localhost:6379",
|
||||||
"AuthSettings": {
|
"AuthSettings": {
|
||||||
"SecretKey": "iJWHDmHLpUA283sqsfhqGbMRdRj1PVkH"
|
"SecretKey": "iJWHDmHLpUA283sqsfhqGbMRdRj1PVkH"
|
||||||
|
},
|
||||||
|
"JwtIssuerOptions": {
|
||||||
|
"Issuer": "SomeIssuer",
|
||||||
|
"Audience": "http://localhost:5000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/.idea
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["BlueWest.Console/BlueWest.Console.csproj", "BlueWest.Console/"]
|
||||||
|
RUN dotnet restore "BlueWest.Console/BlueWest.Console.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/BlueWest.Console"
|
||||||
|
RUN dotnet build "BlueWest.Console.csproj" -c Release -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
RUN dotnet publish "BlueWest.Console.csproj" -c Release -o /app/publish
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "BlueWest.Console.dll"]
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
/*var s = CultureInfo.GetCultures(CultureTypes.AllCultures);
|
||||||
|
|
||||||
|
foreach (var culture in s)
|
||||||
|
{
|
||||||
|
var actualCulture = culture;
|
||||||
|
Console.WriteLine(actualCulture);
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
async Task TaskReceiver(Func<Task> task)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello");
|
||||||
|
await task.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task Task2()
|
||||||
|
{
|
||||||
|
Console.WriteLine("World");
|
||||||
|
}
|
||||||
|
|
||||||
|
var f = Task2;
|
||||||
|
|
||||||
|
await TaskReceiver(f);
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users
|
namespace BlueWest.WebApi.Context.Users
|
||||||
{
|
{
|
||||||
public class AccessToken
|
public class AccessToken
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
public class ApplicationDevice
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public ClientOperatingSystem ClientOperatingSystem { get; set; }
|
||||||
|
public ClientPlatformType ClientPlatformType { get; set; }
|
||||||
|
public string Resolution { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ApplicationDeviceCreate
|
||||||
|
{
|
||||||
|
[Required] public string Uuid;
|
||||||
|
public string Languages { get; set; }
|
||||||
|
public string UserAgent { get; set; }
|
||||||
|
public OperatingSystemType OperatingSystemType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
public enum ClientOperatingSystem
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
WindowsVista,
|
||||||
|
Windows7,
|
||||||
|
Windows8,
|
||||||
|
Windows81,
|
||||||
|
Windows10,
|
||||||
|
Windows2003,
|
||||||
|
WindowsXp,
|
||||||
|
WindowsPhone8,
|
||||||
|
Playstation,
|
||||||
|
Wii,
|
||||||
|
Linux,
|
||||||
|
Linux64,
|
||||||
|
Curl,
|
||||||
|
Bada,
|
||||||
|
Iphone,
|
||||||
|
Ipad,
|
||||||
|
ChromeOs,
|
||||||
|
Osxx,
|
||||||
|
OsxElCapitan,
|
||||||
|
OsxYosemite,
|
||||||
|
OsxMavericks,
|
||||||
|
OsxMountainLion,
|
||||||
|
OsxPuma,
|
||||||
|
OsxPanther,
|
||||||
|
OsxJaguar,
|
||||||
|
OsxCheetah,
|
||||||
|
OsxLeopard,
|
||||||
|
OsxSnowLeopard,
|
||||||
|
MacOsSierra,
|
||||||
|
OsxLion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace BlueWest.Data.Application;
|
||||||
|
|
||||||
|
public enum ClientPlatformType
|
||||||
|
{
|
||||||
|
MicrosoftWindows,
|
||||||
|
WindowsPhone,
|
||||||
|
IPhone,
|
||||||
|
Samsung,
|
||||||
|
Unknown,
|
||||||
|
Wii,
|
||||||
|
Linux,
|
||||||
|
Blackberry,
|
||||||
|
Playstation,
|
||||||
|
Ipad,
|
||||||
|
IPod,
|
||||||
|
Curl
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
public enum OperatingSystemType
|
||||||
|
{
|
||||||
|
MacOS,
|
||||||
|
iOS,
|
||||||
|
Windows,
|
||||||
|
Android,
|
||||||
|
Linux
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using BlueWest.Data;
|
using BlueWest.Data;
|
||||||
|
using BlueWest.Data.Application;
|
||||||
using MapTo;
|
using MapTo;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
@ -20,10 +21,8 @@ namespace BlueWest.WebApi.Context.Users
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
[PersonalData]
|
[PersonalData]
|
||||||
public new string Id { get; set; }
|
public override string Id { get; set; }
|
||||||
|
|
||||||
public List<User> Users { get; set; }
|
|
||||||
|
|
||||||
[ProtectedPersonalData]
|
[ProtectedPersonalData]
|
||||||
public override string UserName { get; set; }
|
public override string UserName { get; set; }
|
||||||
|
|
||||||
|
@ -97,5 +96,11 @@ namespace BlueWest.WebApi.Context.Users
|
||||||
/// Gets or sets the number of failed login attempts for the current user.
|
/// Gets or sets the number of failed login attempts for the current user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override int AccessFailedCount { get; set; }
|
public override int AccessFailedCount { get; set; }
|
||||||
|
|
||||||
|
public List<SessionToken> SessionToken { get; set; }
|
||||||
|
|
||||||
|
public List<SessionData> SessionDatas { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class ApplicationUserToken : IdentityUserToken<string>
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\include\BlueWest.MapTo\src\BlueWest.MapTo\BlueWest.MapTo.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
|
<ProjectReference Include="..\include\Math-Expression-Evaluator\SimpleExpressionEvaluator\SimpleExpressionEvaluator.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="obj\rider.project.restore.info" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.8" />
|
||||||
|
<PackageReference Include="Redis.OM" Version="0.2.2" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="..\include\BlueWest.MapTo\src\BlueWest.MapTo\MapTo.props" />
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Context.Users
|
||||||
|
{
|
||||||
|
public interface IJwtTokenHandler
|
||||||
|
{
|
||||||
|
string WriteToken(JwtSecurityToken jwt);
|
||||||
|
ClaimsPrincipal ValidateToken(string token, TokenValidationParameters tokenValidationParameters);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
internal interface ITokenFactory
|
||||||
|
{
|
||||||
|
string GenerateToken(int size= 32);
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
internal class JwtIssuerOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.1. "iss" (Issuer) Claim - The "iss" (issuer) claim identifies the principal that issued the JWT.
|
||||||
|
/// </summary>
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.2. "sub" (Subject) Claim - The "sub" (subject) claim identifies the principal that is the subject of the JWT.
|
||||||
|
/// </summary>
|
||||||
|
public string Subject { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.3. "aud" (Audience) Claim - The "aud" (audience) claim identifies the recipients that the JWT is intended for.
|
||||||
|
/// </summary>
|
||||||
|
public string Audience { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.4. "exp" (Expiration Time) Claim - The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Expiration => IssuedAt.Add(ValidFor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.5. "nbf" (Not Before) Claim - The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime NotBefore => DateTime.UtcNow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4.1.6. "iat" (Issued At) Claim - The "iat" (issued at) claim identifies the time at which the JWT was issued.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime IssuedAt => DateTime.UtcNow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the timespan the token will be valid for (default is 120 min)
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan ValidFor { get; set; } = TimeSpan.FromMinutes(120);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "jti" (JWT ID) Claim (default ID is a GUID)
|
||||||
|
/// </summary>
|
||||||
|
public Func<Task<string>> JtiGenerator =>
|
||||||
|
() => Task.FromResult(Guid.NewGuid().ToString());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The signing key to use when generating tokens.
|
||||||
|
/// </summary>
|
||||||
|
public SigningCredentials SigningCredentials { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
public class JwtTokenHandler : IJwtTokenHandler
|
||||||
|
{
|
||||||
|
private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JwtTokenHandler
|
||||||
|
/// </summary>
|
||||||
|
public JwtTokenHandler()
|
||||||
|
{
|
||||||
|
_jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jwt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string WriteToken(JwtSecurityToken jwt)
|
||||||
|
{
|
||||||
|
return _jwtSecurityTokenHandler.WriteToken(jwt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validate Token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <param name="tokenValidationParameters"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="SecurityTokenException"></exception>
|
||||||
|
public ClaimsPrincipal ValidateToken(string token, TokenValidationParameters tokenValidationParameters)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var principal = _jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);
|
||||||
|
|
||||||
|
if (!(securityToken is JwtSecurityToken jwtSecurityToken) || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
throw new SecurityTokenException("Invalid token");
|
||||||
|
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Redis.OM.Modeling;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
public class SessionCacheItem
|
||||||
|
{
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
[RedisIdField] [Indexed]
|
||||||
|
public string SessionTokenId { get; set; }
|
||||||
|
|
||||||
|
[Indexed]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using BlueWest.WebApi.Context.Users;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
public class SessionData
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
public string SessionTokenId { get; set; }
|
||||||
|
public SessionToken SessionToken { get; set; }
|
||||||
|
public ApplicationUser User { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
using BlueWest.WebApi.Context.Users;
|
||||||
|
using MapTo;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
[MapFrom(new []
|
||||||
|
{
|
||||||
|
typeof(SessionTokenUnique)
|
||||||
|
})]
|
||||||
|
public partial class SessionToken
|
||||||
|
{
|
||||||
|
[IgnoreMemberMapTo]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string Token { get; set; }
|
||||||
|
public TimeSpan ValidFor { get; set;}
|
||||||
|
|
||||||
|
public bool IsValid { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedDate { get; set; }
|
||||||
|
|
||||||
|
public ApplicationUser User { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
public ApplicationDevice ApplicationDevice { get; set; }
|
||||||
|
|
||||||
|
public SessionData SessionData { get; set; }
|
||||||
|
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using MapTo;
|
||||||
|
|
||||||
|
namespace BlueWest.Data.Application
|
||||||
|
{
|
||||||
|
[MapFrom(typeof(SessionToken))]
|
||||||
|
public partial class SessionTokenUnique
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string Token { get; set; }
|
||||||
|
public TimeSpan ValidFor { get; set;}
|
||||||
|
public DateTime CreatedDate { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
|
|
||||||
namespace BlueWest.WebApi.Context.Users;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public class ApplicationUserToken : IdentityUserToken<string> { }
|
|
|
@ -17,11 +17,12 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.7" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.7" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Folder Include="Application" />
|
||||||
<Folder Include="Capital" />
|
<Folder Include="Capital" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="..\include\BlueWest.MapTo\src\BlueWest.MapTo\MapTo.props" />
|
<Import Project="..\include\BlueWest.MapTo\src\BlueWest.MapTo\MapTo.props" />
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2afc7cc1eb60369db3d2db021d514647baba93dc
|
Subproject commit b67ba4a1a6bb8a58ee44b34dbadbd6a0e99c5c87
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace BlueWest.Posts
|
||||||
|
{
|
||||||
|
public class PostType
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
BlueWest.sln
18
BlueWest.sln
|
@ -36,6 +36,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.Api.Gateway", "Blu
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.EfMethods", "include\BlueWest.EfMethods\src\BlueWest.EfMethods\BlueWest.EfMethods.csproj", "{BBF5E860-A880-450B-B6C9-EF92F6421B3D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.EfMethods", "include\BlueWest.EfMethods\src\BlueWest.EfMethods\BlueWest.EfMethods.csproj", "{BBF5E860-A880-450B-B6C9-EF92F6421B3D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Data.Application", "BlueWest.Data.Application\BlueWest.Data.Application.csproj", "{F0F4A1F3-E279-4374-B146-1E1D82011574}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Console", "BlueWest.Console\BlueWest.Console.csproj", "{D50ED30A-B560-4D00-8D56-653F994045CE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Posts", "BlueWest.Posts\BlueWest.Posts.csproj", "{78540D1E-240F-41FF-B8ED-A265DD5ADCB5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -78,6 +84,18 @@ Global
|
||||||
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{BBF5E860-A880-450B-B6C9-EF92F6421B3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F0F4A1F3-E279-4374-B146-1E1D82011574}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F0F4A1F3-E279-4374-B146-1E1D82011574}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F0F4A1F3-E279-4374-B146-1E1D82011574}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F0F4A1F3-E279-4374-B146-1E1D82011574}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D50ED30A-B560-4D00-8D56-653F994045CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D50ED30A-B560-4D00-8D56-653F994045CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D50ED30A-B560-4D00-8D56-653F994045CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D50ED30A-B560-4D00-8D56-653F994045CE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{78540D1E-240F-41FF-B8ED-A265DD5ADCB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{78540D1E-240F-41FF-B8ED-A265DD5ADCB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{78540D1E-240F-41FF-B8ED-A265DD5ADCB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{78540D1E-240F-41FF-B8ED-A265DD5ADCB5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace BlueWest.Tools
|
namespace BlueWest.Tools
|
||||||
{
|
{
|
||||||
|
@ -83,8 +85,8 @@ namespace BlueWest.Tools
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
List<EventListenerBase> list = _subscribersList[type];
|
List<EventListenerBase> list = _subscribersList[type];
|
||||||
|
|
||||||
for (int i=0; i<list.Count; i++)
|
for (int i=0; i<list.Count; i++)
|
||||||
{
|
{
|
||||||
var eventListener = list[i];
|
var eventListener = list[i];
|
||||||
var casted = eventListener as EventListener<TEvent>;
|
var casted = eventListener as EventListener<TEvent>;
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace PerformanceSolution
|
||||||
|
|
||||||
void StartServer()
|
void StartServer()
|
||||||
{
|
{
|
||||||
string ip = "127.0.0.1";
|
string ip = "127.0.0-preview.7.22376.2.1";
|
||||||
int port = 80;
|
int port = 80;
|
||||||
var server = new TcpListener(IPAddress.Parse(ip), port);
|
var server = new TcpListener(IPAddress.Parse(ip), port);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ services:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: ./BlueWest.Api/Dockerfile
|
dockerfile: ./BlueWest.Api/Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- 8080:80
|
- "8080:80"
|
||||||
environment:
|
environment:
|
||||||
VIRTUAL_HOST: localhost
|
VIRTUAL_HOST: localhost
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -35,4 +35,11 @@ services:
|
||||||
- db:db
|
- db:db
|
||||||
container_name: BW1_API
|
container_name: BW1_API
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
command: redis-server --requirepass Sup3rSecurePass0rd
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- REDIS_REPLICATION_MODE=master
|
||||||
|
|
Loading…
Reference in New Issue