Session wip
This commit is contained in:
parent
e0e9df2edd
commit
3b8d82049f
|
@ -12,16 +12,18 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<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.Policy" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" 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>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -42,6 +44,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BlueWest.Data.Application\BlueWest.Data.Application.csproj" />
|
||||
<ProjectReference Include="..\BlueWest.Data.Capital\BlueWest.Data.Capital.csproj" />
|
||||
<ProjectReference Include="..\BlueWest\BlueWest.csproj" />
|
||||
<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))]
|
||||
public sealed override DbSet<ApplicationUserClaim> UserClaims { get; set; }
|
||||
|
||||
[EfGetMany(typeof(ApplicationUserRoleUnique))]
|
||||
/// <inheritdoc />
|
||||
[EfGetMany(typeof(ApplicationUserRoleUnique))]
|
||||
public sealed override DbSet<ApplicationUserRole> UserRoles { get; set; }
|
||||
|
||||
[EfGetMany(typeof(ApplicationRoleUnique))]
|
||||
/// <inheritdoc />
|
||||
[EfGetMany(typeof(ApplicationRoleUnique))]
|
||||
public sealed override DbSet<ApplicationRole> Roles { get; set; }
|
||||
|
||||
[EfGetMany(typeof(ApplicationRoleClaimUnique))]
|
||||
/// <inheritdoc />
|
||||
[EfGetMany(typeof(ApplicationRoleClaimUnique))]
|
||||
public sealed override DbSet<ApplicationRoleClaim> RoleClaims { get; set; }
|
||||
|
||||
[EfGetMany(typeof(ApplicationUserUnique))]
|
||||
[EfUpdateMethods( updateType: typeof(ApplicationUserUnique), returnType: typeof(ApplicationUserUnique), keyPropertyMemberName: nameof(ApplicationUserUnique.Id))]
|
||||
public sealed override DbSet<ApplicationUser> Users { get; set; }
|
||||
|
||||
#region Initialization
|
||||
|
||||
/// <inheritdoc />
|
||||
#region Initialization
|
||||
public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options) : base(options)
|
||||
{
|
||||
Database.EnsureCreated();
|
||||
|
@ -55,62 +54,13 @@ namespace BlueWest.WebApi.Context
|
|||
{
|
||||
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();
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <inheritdoc />
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using BlueWest.Data;
|
||||
using BlueWest.Data.Application;
|
||||
using BlueWest.WebApi.Context.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -11,9 +12,7 @@ namespace BlueWest.WebApi.EF.Model
|
|||
{
|
||||
#region Initialization
|
||||
|
||||
static ModelBuilderExtensions()
|
||||
{
|
||||
}
|
||||
static ModelBuilderExtensions() { }
|
||||
|
||||
/// <summary>
|
||||
/// Setup the database model
|
||||
|
@ -24,7 +23,101 @@ namespace BlueWest.WebApi.EF.Model
|
|||
modelBuilder
|
||||
.ConfigureDatabaseKeys()
|
||||
.CurrencyModel()
|
||||
.ConfigureUserModel();
|
||||
.ConfigureUserModel()
|
||||
.ConfigureAppContextModel();
|
||||
|
||||
//.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();
|
||||
}
|
||||
|
@ -121,48 +214,11 @@ namespace BlueWest.WebApi.EF.Model
|
|||
.WithMany(ft => ft.FinanceTransactions)
|
||||
.HasForeignKey(x => x.UserId));
|
||||
|
||||
modelBuilder.Entity<User>(b => b.HasOne<ApplicationUser>()
|
||||
.WithMany(x => x.Users)
|
||||
.HasForeignKey(x => x.ApplicationUserId));
|
||||
|
||||
return modelBuilder;
|
||||
}
|
||||
|
||||
#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.WebApi.Context;
|
||||
using BlueWest.WebApi.Context.Users;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
|
||||
namespace BlueWest.WebApi.Controllers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[ApiController]
|
||||
[Route("application/users")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
|
@ -19,6 +21,7 @@ namespace BlueWest.WebApi.Controllers
|
|||
{
|
||||
private readonly ApplicationUserDbContext _dbContext;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ApplicationUserController(ApplicationUserDbContext context)
|
||||
{
|
||||
_dbContext = context;
|
||||
|
@ -54,16 +57,15 @@ namespace BlueWest.WebApi.Controllers
|
|||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[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)
|
||||
{
|
||||
return Ok(User);
|
||||
return Ok(updatedUser);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
@ -124,8 +126,14 @@ namespace BlueWest.WebApi.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Application Constants
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Policy Name
|
||||
/// </summary>
|
||||
public const string CorsPolicyName = "_myAllowSpecificOrigins";
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Cryptography;
|
||||
using BlueWest.Data.Application;
|
||||
using BlueWest.WebApi.Context.Users;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
|
@ -14,25 +17,28 @@ namespace BlueWest.WebApi.Controllers;
|
|||
/// <summary>
|
||||
/// Auth controller
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||
[ApiController]
|
||||
[EnableCors(Constants.CorsPolicyName)]
|
||||
public class AuthController : Controller
|
||||
[Route("api/[controller]")]
|
||||
|
||||
[Authorize(Policy = "ApiUser")]
|
||||
|
||||
/*[EnableCors(Constants.CorsPolicyName)]*/
|
||||
public class AuthController : Controller
|
||||
{
|
||||
private readonly IAuthManager _authManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="authManager"></param>
|
||||
/// <param name="userManager"></param>
|
||||
public AuthController( IAuthManager authManager, IUserManager userManager)
|
||||
public AuthController( IAuthManager authManager, IUserManager userManager, ISessionManager sessionManager)
|
||||
{
|
||||
_authManager = authManager;
|
||||
_userManager = userManager;
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,49 +55,87 @@ public class AuthController : Controller
|
|||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a bearer token
|
||||
/// </summary>
|
||||
/// <param name="loginViewModel"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<ActionResult<IdentityResult>> GetTokenAsync(LoginViewModel loginViewModel)
|
||||
[HttpPost("token")]
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <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>
|
||||
/// Do Cookie based login.
|
||||
/// </summary>
|
||||
/// <param name="loginDto"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("logincookie")]
|
||||
public async Task<ActionResult<IdentityResult>> DoLoginAsync(LoginViewModel loginDto)
|
||||
[HttpPost("login")]
|
||||
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,
|
||||
new ClaimsPrincipal(identity),
|
||||
new AuthenticationProperties
|
||||
{
|
||||
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
||||
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>
|
||||
|
@ -101,10 +145,9 @@ public class AuthController : Controller
|
|||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("logout")]
|
||||
public async Task<ActionResult<IdentityResult>> DoLogoutAsync(LoginViewModel loginDto)
|
||||
public async Task DoLogoutAsync()
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return Json(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,7 @@ namespace BlueWest.WebApi.Controllers
|
|||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||
[Authorize(Policy = "ApiUser")]
|
||||
[EnableCors(Constants.CorsPolicyName)]
|
||||
// [Authorize(Roles = "Administrator")]
|
||||
public class CountryController : ControllerBase
|
||||
|
|
|
@ -6,6 +6,7 @@ using BlueWest.WebApi.EF;
|
|||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -18,6 +19,8 @@ namespace BlueWest.WebApi.Controllers
|
|||
[Route("[controller]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||
[EnableCors(Constants.CorsPolicyName)]
|
||||
|
||||
// [Authorize(Roles = "Administrator")]
|
||||
public partial class CurrencyController : ControllerBase
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ using BlueWest.WebApi.EF;
|
|||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -16,7 +17,9 @@ namespace BlueWest.WebApi.Controllers;
|
|||
[Route("[controller]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||
[Authorize(Roles = "Administrator")]
|
||||
//[Authorize(Roles = "Administrator")]
|
||||
[EnableCors(Constants.CorsPolicyName)]
|
||||
|
||||
public class FinanceController : ControllerBase
|
||||
{
|
||||
private readonly FinanceDbContext _dbContext;
|
||||
|
|
|
@ -7,6 +7,7 @@ using BlueWest.WebApi.EF;
|
|||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -19,7 +20,8 @@ namespace BlueWest.WebApi.Controllers
|
|||
[Route("[controller]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
|
||||
[Authorize(Roles = "Administrator")]
|
||||
//[Authorize(Roles = "Administrator")]
|
||||
[EnableCors(Constants.CorsPolicyName)]
|
||||
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
|
|
|
@ -15,8 +15,8 @@ COPY ["BlueWest/BlueWest.csproj", "BlueWest/"]
|
|||
RUN dotnet restore "BlueWest/BlueWest.csproj"
|
||||
|
||||
|
||||
COPY ["BlueWest.Data.Geography/BlueWest.Data.Geography.csproj", "BlueWest.Data.Geography/"]
|
||||
RUN dotnet restore "BlueWest.Data.Geography/BlueWest.Data.Geography.csproj"
|
||||
COPY ["BlueWest.Data.Application/BlueWest.Data.Application.csproj", "BlueWest.Data.Application/"]
|
||||
RUN dotnet restore "BlueWest.Data.Application/BlueWest.Data.Application.csproj"
|
||||
|
||||
|
||||
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 System.Text.Json.Serialization;
|
||||
using BlueWest.Tools;
|
||||
using BlueWest.WebApi.Context.Users;
|
||||
using BlueWest.WebApi.Interceptors;
|
||||
using BlueWest.WebApi.Interfaces;
|
||||
using BlueWest.WebApi.Tools;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace BlueWest.WebApi
|
||||
|
@ -24,6 +23,7 @@ namespace BlueWest.WebApi
|
|||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
private readonly string MyAllowSpecificOrigins = Constants.CorsPolicyName;
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,7 +47,7 @@ namespace BlueWest.WebApi
|
|||
options.AddPolicy(name: MyAllowSpecificOrigins,
|
||||
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()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials();
|
||||
|
@ -55,9 +55,27 @@ namespace BlueWest.WebApi
|
|||
});
|
||||
|
||||
services
|
||||
.AddControllers()
|
||||
.AddResponseCaching()
|
||||
.AddControllers(options =>
|
||||
{
|
||||
options.CacheProfiles.Add("Default30",
|
||||
new CacheProfile()
|
||||
{
|
||||
Duration = 30
|
||||
});
|
||||
})
|
||||
.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
|
||||
.AddSwaggerGen(options =>
|
||||
{
|
||||
|
@ -102,6 +120,13 @@ namespace BlueWest.WebApi
|
|||
|
||||
});
|
||||
|
||||
|
||||
services.AddGrpc(options =>
|
||||
{
|
||||
options.Interceptors.Add<ServerLoggerInterceptor>();
|
||||
});
|
||||
|
||||
services.AddSingleton<ServerLoggerInterceptor>();
|
||||
/*
|
||||
services.AddSingleton<IFileProvider>(
|
||||
new PhysicalFileProvider(
|
||||
|
@ -120,9 +145,11 @@ namespace BlueWest.WebApi
|
|||
services
|
||||
.AddSingleton<EventManager>();
|
||||
|
||||
services.AddAuthServerServices(MyAllowSpecificOrigins, _configuration, _environment);
|
||||
|
||||
services.AddAuthServerServices( _configuration, _environment);
|
||||
services.AddScoped<ExchangeInterface>();
|
||||
|
||||
|
||||
switch (allowedDatabase)
|
||||
{
|
||||
case "mysql":
|
||||
|
@ -138,10 +165,6 @@ namespace BlueWest.WebApi
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// services.AddGrpc();
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,19 +179,17 @@ namespace BlueWest.WebApi
|
|||
|
||||
//app.UseStaticFiles();
|
||||
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseSwagger();
|
||||
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.RoutePrefix = "swagger";
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.Api v1");
|
||||
});
|
||||
|
||||
app.UseStaticFiles();
|
||||
//app.UseHttpsRedirection();
|
||||
|
||||
|
||||
|
||||
|
||||
app.UseRouting();
|
||||
app.UseCors(MyAllowSpecificOrigins);
|
||||
app.UseAuthentication();
|
||||
|
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication.Cookies;
|
|||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
@ -80,7 +81,9 @@ namespace BlueWest.WebApi
|
|||
.AddDbContextPool<CountryDbContext>(options => options.GetMySqlSettings(configuration, environment))
|
||||
.AddDbContextPool<FinanceDbContext>(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>
|
||||
|
@ -100,27 +103,24 @@ namespace BlueWest.WebApi
|
|||
.AddDbContextPool<CountryDbContext>(options => options.UseSqlite(sqliteConString))
|
||||
.AddDbContextPool<FinanceDbContext>(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<IJwtFactory, JwtFactory>();
|
||||
|
||||
|
||||
services
|
||||
.AddScoped< UserRepository>()
|
||||
services.AddScoped<IJwtTokenHandler, JwtTokenHandler>()
|
||||
.AddScoped<IJwtFactory, JwtFactory>()
|
||||
.AddSingleton<IndexCreationDevice>()
|
||||
.AddScoped<ISessionManager, SessionManager>()
|
||||
.AddScoped<UserRepository>()
|
||||
.AddScoped<IUserManager, ApplicationUserManager>()
|
||||
.AddScoped<IAuthManager, AuthManager>()
|
||||
|
||||
.AddScoped<IHasher, Hasher>();
|
||||
|
||||
services
|
||||
.AddIdentityCore<ApplicationUser>(opt => { opt.User.RequireUniqueEmail = true; })
|
||||
.AddUserManager<ApplicationUserManager>()
|
||||
.AddUserStore<UserRepository>();
|
||||
// Database Context and Swagger
|
||||
|
||||
|
||||
|
@ -162,6 +162,7 @@ namespace BlueWest.WebApi
|
|||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
|
@ -170,6 +171,9 @@ namespace BlueWest.WebApi
|
|||
})
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.Cookie.SameSite = SameSiteMode.Lax;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
||||
options.Cookie.MaxAge = TimeSpan.FromDays(1);
|
||||
options.LoginPath = "/api/auth/logincookie";
|
||||
options.LogoutPath = "/api/auth/logout";
|
||||
})
|
||||
|
@ -206,13 +210,17 @@ namespace BlueWest.WebApi
|
|||
// add identity
|
||||
var identityBuilder = services.AddIdentityCore<ApplicationUser>(o =>
|
||||
{
|
||||
o.User.RequireUniqueEmail = true;
|
||||
|
||||
// configure identity options
|
||||
o.Password.RequireDigit = false;
|
||||
o.Password.RequireLowercase = false;
|
||||
o.Password.RequireUppercase = false;
|
||||
o.Password.RequireNonAlphanumeric = false;
|
||||
o.Password.RequiredLength = 6;
|
||||
});
|
||||
})
|
||||
.AddUserManager<ApplicationUserManager>()
|
||||
.AddUserStore<UserRepository>();
|
||||
|
||||
identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services);
|
||||
identityBuilder
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Cryptography;
|
||||
using BlueWest.Data.Application;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
@ -16,12 +17,16 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
|||
{
|
||||
private readonly IHasher _hasher;
|
||||
private readonly UserRepository _usersRepo;
|
||||
public ApplicationUserManager(UserRepository store, IOptions<IdentityOptions> optionsAccessor,
|
||||
IHasher passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
|
||||
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
|
||||
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store,
|
||||
optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services,
|
||||
logger)
|
||||
public ApplicationUserManager(
|
||||
UserRepository store,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IHasher passwordHasher,
|
||||
IEnumerable<IUserValidator<ApplicationUser>> userValidators,
|
||||
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;
|
||||
_usersRepo = store;
|
||||
|
@ -49,6 +54,7 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
|||
return success;
|
||||
}
|
||||
|
||||
|
||||
protected override async Task<PasswordVerificationResult> VerifyPasswordAsync(IUserPasswordStore<ApplicationUser> store, ApplicationUser user, string password)
|
||||
{
|
||||
string existingHash;
|
||||
|
@ -90,6 +96,10 @@ internal class ApplicationUserManager : UserManager<ApplicationUser>, IUserManag
|
|||
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()
|
||||
{
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Cryptography;
|
||||
using BlueWest.Data.Application;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace BlueWest.WebApi.Context.Users;
|
||||
|
||||
internal class AuthManager : IAuthManager
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ApplicationUserManager _userManager;
|
||||
private readonly UserRepository _usersRepo;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly IHasher _hasher;
|
||||
private readonly IJwtFactory _jwtFactory;
|
||||
|
||||
|
@ -19,51 +25,79 @@ internal class AuthManager : IAuthManager
|
|||
/// <param name="hasher"></param>
|
||||
/// <param name="usersRepo"></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;
|
||||
_hasher = hasher;
|
||||
_usersRepo = usersRepo;
|
||||
_jwtFactory = jwtFactory;
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<AccessToken> GetToken(LoginViewModel loginViewModel)
|
||||
public async Task<(bool, ClaimsIdentity, SessionTokenUnique)> DoLogin(LoginRequest loginRequest)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(loginViewModel.Email) && !string.IsNullOrEmpty(loginViewModel.Password))
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(loginViewModel.Email);
|
||||
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
if (await VerifyLoginAsync(loginViewModel.Email,loginViewModel.Password))
|
||||
if(await _userManager.CheckPasswordAsync(user, loginRequest.Password))
|
||||
{
|
||||
// Todo generate refresh token
|
||||
// Todo Add refresh token
|
||||
await _usersRepo.UpdateAsync(user, CancellationToken.None);
|
||||
var token = await _jwtFactory.GenerateEncodedToken(user.Id.ToString(), user.UserName);
|
||||
// await _userManager.SetAuthenticationTokenAsync(user, "Income", "ApiUser", token.Token);
|
||||
// Identity
|
||||
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
||||
|
||||
return token;
|
||||
}
|
||||
// Session
|
||||
var sessionToken = _sessionManager.GetSessionToken(loginRequest, user);
|
||||
var sessionResponse = new SessionTokenUnique(sessionToken);
|
||||
return (true, identity, sessionResponse);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return (false, null, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> VerifyLoginAsync(string email, string password)
|
||||
public async Task<(bool, SessionTokenUnique, AccessToken)> GetToken(LoginRequest loginRequest)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(loginRequest.Email) && !string.IsNullOrEmpty(loginRequest.Password))
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
||||
if (user != null)
|
||||
{
|
||||
if (await VerifyLoginByEmailAsync(loginRequest.Email,loginRequest.Password))
|
||||
{
|
||||
await _usersRepo.UpdateAsync(user, CancellationToken.None);
|
||||
// Session
|
||||
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 (completed == IdentityResult.Success, sessionResponse, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (false, null, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> VerifyLoginByEmailAsync(string email, string password)
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(email);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return false; // return error user doesn't exist
|
||||
return false;
|
||||
}
|
||||
|
||||
return await _userManager.CheckPasswordAsync(user, password);
|
||||
|
||||
// return await GenerateAuthenticationResultForUserAsync(user);
|
||||
}
|
||||
|
||||
private RegisterViewModel FromSignupToUser(RegisterViewModel signupDto)
|
||||
|
@ -71,8 +105,6 @@ internal class AuthManager : IAuthManager
|
|||
var pwd = signupDto.Password;
|
||||
var hash = _hasher.CreateHash(pwd, BaseCryptoItem.HashAlgorithm.SHA3_512);
|
||||
signupDto.Password = hash;
|
||||
signupDto.ConfirmPassword = hash;
|
||||
|
||||
return signupDto;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace BlueWest.Cryptography
|
|||
/// <param name="text"></param>
|
||||
/// <param name="algorithm"></param>
|
||||
/// <returns></returns>
|
||||
public string CreateHash(string text, BaseCryptoItem.HashAlgorithm algorithm)
|
||||
public string CreateHash(string text, HashAlgorithm algorithm)
|
||||
{
|
||||
var salt = CreateRandomString(SaltLength);
|
||||
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.Jti, await _jwtOptions.JtiGenerator()),
|
||||
new Claim(JwtRegisteredClaimNames.Aud, _jwtOptions.Audience),
|
||||
|
||||
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
|
||||
ClaimValueTypes.Integer64),
|
||||
identity.FindFirst(JwtClaimIdentifiers.Rol),
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Data.Application;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace BlueWest.WebApi.Context.Users;
|
||||
|
@ -21,13 +24,20 @@ public interface IAuthManager
|
|||
/// <param name="email"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> VerifyLoginAsync(string email, string password);
|
||||
Task<bool> VerifyLoginByEmailAsync(string email, string password);
|
||||
|
||||
/// <summary>
|
||||
/// GetToken
|
||||
/// </summary>
|
||||
/// <param name="loginViewModel"></param>
|
||||
/// <param name="loginRequest"></param>
|
||||
/// <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 BlueWest.Data.Application;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace BlueWest.WebApi.Context.Users
|
||||
|
@ -26,6 +27,9 @@ namespace BlueWest.WebApi.Context.Users
|
|||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
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
|
||||
/// <summary>
|
||||
/// Login View Model
|
||||
/// Login Request adata
|
||||
/// </summary>
|
||||
public class LoginViewModel
|
||||
public class LoginRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Email
|
||||
|
@ -22,11 +22,9 @@ namespace BlueWest.WebApi.Context.Users
|
|||
[DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RememberMe
|
||||
/// </summary>
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
[Required]
|
||||
public string Uuid { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,16 @@ public class RegisterViewModel
|
|||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ConfirmPassword
|
||||
/// </summary>
|
||||
[DataType(DataType.PhoneNumber)]
|
||||
[Display(Name = "Phone Number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert RegisterViewModel to ApplicationUser
|
||||
/// </summary>
|
||||
|
@ -46,6 +56,7 @@ public class RegisterViewModel
|
|||
newUser.Email = Email;
|
||||
newUser.PasswordHash = Password;
|
||||
newUser.UserName = Username;
|
||||
newUser.PhoneNumber = PhoneNumber;
|
||||
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": {
|
||||
"DockerMySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;"
|
||||
},
|
||||
"REDIS_CONNECTION_STRING": "redis://localhost:6379",
|
||||
"AuthSettings": {
|
||||
"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
|
||||
{
|
||||
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.Schema;
|
||||
using BlueWest.Data;
|
||||
using BlueWest.Data.Application;
|
||||
using MapTo;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
|
@ -20,9 +21,7 @@ namespace BlueWest.WebApi.Context.Users
|
|||
/// </summary>
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[PersonalData]
|
||||
public new string Id { get; set; }
|
||||
|
||||
public List<User> Users { get; set; }
|
||||
public override string Id { get; set; }
|
||||
|
||||
[ProtectedPersonalData]
|
||||
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.
|
||||
/// </summary>
|
||||
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>
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Application" />
|
||||
<Folder Include="Capital" />
|
||||
</ItemGroup>
|
||||
<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
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.EfMethods", "include\BlueWest.EfMethods\src\BlueWest.EfMethods\BlueWest.EfMethods.csproj", "{BBF5E860-A880-450B-B6C9-EF92F6421B3D}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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}.Release|Any CPU.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BlueWest.Tools
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace PerformanceSolution
|
|||
|
||||
void StartServer()
|
||||
{
|
||||
string ip = "127.0.0.1";
|
||||
string ip = "127.0.0-preview.7.22376.2.1";
|
||||
int port = 80;
|
||||
var server = new TcpListener(IPAddress.Parse(ip), port);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ services:
|
|||
context: ./
|
||||
dockerfile: ./BlueWest.Api/Dockerfile
|
||||
ports:
|
||||
- 8080:80
|
||||
- "8080:80"
|
||||
environment:
|
||||
VIRTUAL_HOST: localhost
|
||||
restart: always
|
||||
|
@ -35,4 +35,11 @@ services:
|
|||
- db:db
|
||||
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