Upgrade packages and target NET 7.0
This commit is contained in:
parent
87d4a6373a
commit
e70bdee832
|
@ -96,11 +96,6 @@ namespace BlueWest.Data.Application.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; }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,9 +17,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.0" />
|
||||||
<PackageReference Include="Redis.OM" Version="0.2.2" />
|
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="..\include\BlueWest.MapTo\src\BlueWest.MapTo\MapTo.props" />
|
<Import Project="..\include\BlueWest.MapTo\src\BlueWest.MapTo\MapTo.props" />
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
using BlueWest.Data.Application.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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
using BlueWest.Data.Application.Users;
|
|
||||||
using MapTo;
|
|
||||||
using Redis.OM.Modeling;
|
|
||||||
|
|
||||||
namespace BlueWest.Data.Application
|
|
||||||
{
|
|
||||||
[Document(StorageType = StorageType.Json, Prefixes = new []{"SessionToken"})]
|
|
||||||
[MapFrom(new []
|
|
||||||
{
|
|
||||||
typeof(SessionTokenUnique)
|
|
||||||
})]
|
|
||||||
public partial class SessionToken
|
|
||||||
{
|
|
||||||
[IgnoreMemberMapTo]
|
|
||||||
[Indexed] public string Id { get; set; }
|
|
||||||
|
|
||||||
[Indexed] public long ValidFor { get; set;}
|
|
||||||
|
|
||||||
[Indexed] public bool IsValid { get; set; }
|
|
||||||
|
|
||||||
[Indexed] public long CreatedDate { get; set; }
|
|
||||||
|
|
||||||
[Indexed] public string UserId { get; set; }
|
|
||||||
|
|
||||||
[Indexed] public string AccessToken { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public bool Validate()
|
|
||||||
{
|
|
||||||
var expirationDate = CreatedDate + ValidFor;
|
|
||||||
var timeNow = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
||||||
if (expirationDate < timeNow)
|
|
||||||
{
|
|
||||||
IsValid = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
using MapTo;
|
|
||||||
|
|
||||||
namespace BlueWest.Data.Application
|
|
||||||
{
|
|
||||||
[MapFrom(typeof(SessionToken))]
|
|
||||||
public partial class SessionTokenUnique
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
public long ValidFor { get; set;}
|
|
||||||
public long CreatedDate { get; set; }
|
|
||||||
public string UserId { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
<RootNamespace>BlueWest.WebApi</RootNamespace>
|
<RootNamespace>BlueWest.WebApi</RootNamespace>
|
||||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||||
|
@ -18,24 +18,22 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.49.0-pre1" />
|
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="6.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.0" />
|
||||||
<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.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||||
<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.InMemory" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||||
<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.Extensions.Configuration" Version="6.0.2-mauipre.1.22102.15" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="6.0.2-mauipre.1.22054.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,10 @@ namespace BlueWest.WebApi.Configuration
|
||||||
{
|
{
|
||||||
public class ConnectionStringDocker
|
public class ConnectionStringDocker
|
||||||
{
|
{
|
||||||
public string Redis { get; set; }
|
|
||||||
public string MySql { get; set; }
|
public string MySql { get; set; }
|
||||||
}
|
}
|
||||||
public class ConnectionStringNoDocker
|
public class ConnectionStringNoDocker
|
||||||
{
|
{
|
||||||
public string Redis { get; set; }
|
|
||||||
public string MySql { get; set; }
|
public string MySql { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
using BlueWest.Data.Application;
|
|
||||||
using BlueWest.Data.Auth.Context.Users;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
|
|
||||||
namespace BlueWest.Data.Auth
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Methods for handling session cache data.
|
|
||||||
/// </summary>
|
|
||||||
public interface ISessionCache : IHostedService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a Session Token by Id.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tokenId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<SessionToken> GetSessionTokenByIdAsync(string tokenId);
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new session token
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
Task AddSessionToken(SessionToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check for validity of the session
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sessionTokenId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> IsSessionValidAsync(string sessionTokenId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the session is valid
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sessionTokenId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool IsSessionValid(string sessionTokenId);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save Cache
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task SaveAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save Cache
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
void Save();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BlueWest.Data.Application;
|
using BlueWest.Data.Application;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace BlueWest.Data.Auth.Context.Users;
|
namespace BlueWest.Data.Auth.Context.Users;
|
||||||
|
|
||||||
|
@ -9,9 +10,7 @@ public static class AuthConsts
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper object to return a negative callback
|
/// Helper object to return a negative callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static (bool, SessionTokenUnique, ClaimsIdentity) NegativeToken => (false, null, null);
|
public static (ClaimsIdentity, bool) NegativeToken => (null, false);
|
||||||
|
|
||||||
public static (bool, SessionTokenUnique, ClaimsIdentity) OkAuth(SessionTokenUnique sessionTokenUnique, ClaimsIdentity claimsIdentity, bool success = true) => (success, sessionTokenUnique, claimsIdentity);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using BlueWest.Cryptography;
|
using BlueWest.Cryptography;
|
||||||
using BlueWest.Data.Application;
|
|
||||||
using BlueWest.Data.Application.Users;
|
using BlueWest.Data.Application.Users;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using static BlueWest.Data.Auth.Context.Users.AuthConsts;
|
using static BlueWest.Data.Auth.Context.Users.AuthConsts;
|
||||||
|
|
||||||
|
@ -18,7 +15,6 @@ namespace BlueWest.Data.Auth.Context.Users
|
||||||
private readonly ApplicationUserManager _userManager;
|
private readonly ApplicationUserManager _userManager;
|
||||||
private readonly IHasher _hasher;
|
private readonly IHasher _hasher;
|
||||||
private readonly IJwtFactory _jwtFactory;
|
private readonly IJwtFactory _jwtFactory;
|
||||||
private readonly ISessionCache _sessionCache;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Auth manager constructor
|
/// Auth manager constructor
|
||||||
|
@ -30,113 +26,22 @@ namespace BlueWest.Data.Auth.Context.Users
|
||||||
public AuthManager(
|
public AuthManager(
|
||||||
ApplicationUserManager userManager,
|
ApplicationUserManager userManager,
|
||||||
IHasher hasher,
|
IHasher hasher,
|
||||||
IJwtFactory jwtFactory,
|
IJwtFactory jwtFactory)
|
||||||
ISessionCache sessionCache)
|
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_hasher = hasher;
|
_hasher = hasher;
|
||||||
_jwtFactory = jwtFactory;
|
_jwtFactory = jwtFactory;
|
||||||
_sessionCache = sessionCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SessionToken> GetSessionToken(LoginRequest loginRequest)
|
|
||||||
{
|
|
||||||
var uuid = loginRequest.GetUuid();
|
|
||||||
var hashUuid = GetHashFromUuid(uuid);
|
|
||||||
var sessionToken = await _sessionCache.GetSessionTokenByIdAsync(hashUuid);
|
|
||||||
return sessionToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetHashFromUuid(string uuid)
|
private string GetHashFromUuid(string uuid)
|
||||||
{
|
{
|
||||||
return _hasher.CreateHash(uuid, BaseCryptoItem.HashAlgorithm.SHA2_512);
|
return _hasher.CreateHash(uuid, BaseCryptoItem.HashAlgorithm.SHA2_512);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SessionToken GetNewSessionToken(LoginRequest loginRequest, ApplicationUser user)
|
|
||||||
{
|
|
||||||
long timeNow = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
||||||
|
|
||||||
var newToken = new SessionToken
|
|
||||||
{
|
|
||||||
Id = GetHashFromUuid(loginRequest.GetUuid()),
|
|
||||||
UserId = user.Id,
|
|
||||||
CreatedDate = timeNow,
|
|
||||||
IsValid = true,
|
|
||||||
ValidFor = SessionConstants.DefaultSessionMaxAge.Milliseconds
|
|
||||||
};
|
|
||||||
|
|
||||||
return newToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SessionTokenIsValid(SessionToken token)
|
|
||||||
{
|
|
||||||
var hasChanges = token.Validate();
|
|
||||||
|
|
||||||
if (hasChanges)
|
|
||||||
{
|
|
||||||
_sessionCache.SaveAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
return token.IsValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest, string authenticationType = JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
{
|
|
||||||
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
|
||||||
|
|
||||||
if (user == null) return NegativeToken;
|
|
||||||
|
|
||||||
if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken;
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity(authenticationType);
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber));
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
|
||||||
|
|
||||||
|
|
||||||
var sessionToken = await GetSessionToken(loginRequest);
|
|
||||||
|
|
||||||
if (sessionToken == null || !SessionTokenIsValid(sessionToken))
|
|
||||||
{
|
|
||||||
var (success, bearerToken) = await GenerateBearerToken(identity, user);
|
|
||||||
var newSessionToken = GetNewSessionToken(loginRequest, user);
|
|
||||||
await _sessionCache.AddSessionToken(newSessionToken);
|
|
||||||
var tokenUnique = new SessionTokenUnique(newSessionToken);
|
|
||||||
return OkAuth(tokenUnique, identity, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = new SessionTokenUnique(sessionToken);
|
|
||||||
return OkAuth(response, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequestViaCookie(LoginRequest loginRequest, string authenticationType = CookieAuthenticationDefaults.AuthenticationScheme)
|
|
||||||
{
|
|
||||||
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
|
||||||
|
|
||||||
if (user == null) return NegativeToken;
|
|
||||||
|
|
||||||
if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken;
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity(authenticationType);
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber));
|
|
||||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
|
||||||
|
|
||||||
|
|
||||||
var sessionToken = await GetSessionToken(loginRequest);
|
|
||||||
|
|
||||||
if (sessionToken == null || !SessionTokenIsValid(sessionToken))
|
|
||||||
{
|
|
||||||
var newSessionToken = GetNewSessionToken(loginRequest, user);
|
|
||||||
await _sessionCache.AddSessionToken(newSessionToken);
|
|
||||||
var tokenUnique = new SessionTokenUnique(newSessionToken);
|
|
||||||
return OkAuth(tokenUnique, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = new SessionTokenUnique(sessionToken);
|
|
||||||
return OkAuth(response, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task<(bool, string)> GenerateBearerToken(ClaimsIdentity identity, ApplicationUser user)
|
private async Task<(bool, string)> GenerateBearerToken(ClaimsIdentity identity, ApplicationUser user)
|
||||||
{
|
{
|
||||||
|
@ -171,5 +76,22 @@ namespace BlueWest.Data.Auth.Context.Users
|
||||||
var newUser = userSignupDto.ToUser();
|
var newUser = userSignupDto.ToUser();
|
||||||
return await _userManager.CreateAsync(newUser);
|
return await _userManager.CreateAsync(newUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<(ClaimsIdentity, bool)> DoLogin(LoginRequest loginRequest)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(loginRequest.Email);
|
||||||
|
|
||||||
|
if (user == null) return NegativeToken;
|
||||||
|
|
||||||
|
if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken;
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber));
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
||||||
|
|
||||||
|
|
||||||
|
return (identity, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,23 +17,11 @@ public interface IAuthManager
|
||||||
/// <param name="registerRequest"></param>
|
/// <param name="registerRequest"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IdentityResult> CreateUserAsync(RegisterRequest registerRequest);
|
Task<IdentityResult> CreateUserAsync(RegisterRequest registerRequest);
|
||||||
|
|
||||||
/// <summary>
|
Task<(ClaimsIdentity, bool)> DoLogin(LoginRequest loginRequest);
|
||||||
/// Does Login
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="loginRequest"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest, string authenticationType);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does Login
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="loginRequest"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequestViaCookie(LoginRequest loginRequest, string authenticationType);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,8 +17,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
@ -10,24 +10,23 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.50.0-pre1" />
|
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="6.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.0" />
|
||||||
<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.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||||
<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.InMemory" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||||
<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.Extensions.Configuration" Version="6.0.2-mauipre.1.22102.15" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="6.0.2-mauipre.1.22054.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
|
<PackageReference Include="Npgsql" Version="7.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -86,26 +86,7 @@ namespace CodeLiturgy.Domain.Model
|
||||||
|
|
||||||
builder.Entity<ApplicationRoleClaim>().ToTable("RoleClaims");
|
builder.Entity<ApplicationRoleClaim>().ToTable("RoleClaims");
|
||||||
builder.Entity<ApplicationUserRole>().ToTable("UserRole");
|
builder.Entity<ApplicationUserRole>().ToTable("UserRole");
|
||||||
|
|
||||||
|
|
||||||
// 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 Primary Key
|
|
||||||
builder.Entity<SessionData>(b =>
|
|
||||||
b.HasKey(x => x.Id));
|
|
||||||
builder.Entity<SessionData>(b =>
|
|
||||||
b.Property(x => x.Id).ValueGeneratedOnAdd());
|
|
||||||
|
|
||||||
|
|
||||||
//.ConfigureIdentityModel();
|
//.ConfigureIdentityModel();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.9" />
|
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.9" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -28,12 +28,11 @@ namespace CodeLiturgy.Views.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Microsoft.AspNetCore.Mvc.ActionName("LoginAction")]
|
[ActionName("LoginAction")]
|
||||||
public async Task<IActionResult> LoginAction(LoginRequest loginRequest)
|
public async Task<IActionResult> LoginAction(LoginRequest loginRequest)
|
||||||
{
|
{
|
||||||
var (success, sessionToken, identity) =
|
var (identity,success) =
|
||||||
await _authManager.GetSessionTokenIdByLoginRequestViaCookie(loginRequest,
|
await _authManager.DoLogin(loginRequest);
|
||||||
CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
|
|
||||||
|
|
||||||
if (!success) return Redirect(AuthLoginRoute);
|
if (!success) return Redirect(AuthLoginRoute);
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using BlueWest.Data.Application;
|
|
||||||
using BlueWest.Data.Auth;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Redis.OM;
|
|
||||||
using Redis.OM.Searching;
|
|
||||||
|
|
||||||
namespace CodeLiturgy.Views;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Session Provider Context
|
|
||||||
/// </summary>
|
|
||||||
public sealed class SessionManager : ISessionCache
|
|
||||||
{
|
|
||||||
private readonly RedisConnectionProvider _provider;
|
|
||||||
private readonly RedisCollection<SessionToken> _sessionTokens;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Index Creation Device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider">Redis connection</param>
|
|
||||||
public SessionManager(
|
|
||||||
RedisConnectionProvider provider)
|
|
||||||
{
|
|
||||||
_provider = provider;
|
|
||||||
_sessionTokens = (RedisCollection<SessionToken>) provider.RedisCollection<SessionToken>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Empty constructor
|
|
||||||
/// </summary>
|
|
||||||
public SessionManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a session token by the respective Id.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tokenId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<SessionToken> GetSessionTokenByIdAsync(string tokenId)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
await _sessionTokens.Where(x => x.Id == tokenId)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new session token
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
public async Task AddSessionToken(SessionToken token)
|
|
||||||
{
|
|
||||||
await _sessionTokens.InsertAsync(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task SaveAsync()
|
|
||||||
{
|
|
||||||
await _sessionTokens.SaveAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save session data
|
|
||||||
/// </summary>
|
|
||||||
public void Save()
|
|
||||||
{
|
|
||||||
_sessionTokens.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a Bearer By Access Token Id
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sessionTokenId"></param>
|
|
||||||
public async Task<bool> IsSessionValidAsync(string sessionTokenId)
|
|
||||||
{
|
|
||||||
var accessToken = await _sessionTokens
|
|
||||||
.Where(t => t.Id == sessionTokenId)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (accessToken == null) return false;
|
|
||||||
|
|
||||||
if (accessToken.IsValid)
|
|
||||||
{
|
|
||||||
// Check if it's not expired
|
|
||||||
var expirationDate = accessToken.CreatedDate + accessToken.ValidFor;
|
|
||||||
var timeNow = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
||||||
if (expirationDate >= timeNow) return accessToken.IsValid;
|
|
||||||
accessToken.IsValid = false;
|
|
||||||
await _sessionTokens.SaveAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
return accessToken.IsValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a session is valid
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sessionTokenId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool IsSessionValid(string sessionTokenId)
|
|
||||||
{
|
|
||||||
var accessToken = _sessionTokens
|
|
||||||
.FirstOrDefault(t => t.Id == sessionTokenId);
|
|
||||||
|
|
||||||
if (accessToken == null) return false;
|
|
||||||
|
|
||||||
if (!accessToken.IsValid) return accessToken.IsValid;
|
|
||||||
|
|
||||||
accessToken.Validate();
|
|
||||||
_sessionTokens.Save();
|
|
||||||
|
|
||||||
return accessToken.IsValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await _provider.Connection.CreateIndexAsync(typeof(SessionToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -46,7 +46,7 @@ public class Startup
|
||||||
|
|
||||||
|
|
||||||
services.AddAuthServerServices(_configuration, _environment);
|
services.AddAuthServerServices(_configuration, _environment);
|
||||||
services.PrepareMySqlDatabasePool(_configuration, _environment);
|
services.PreparePostgresqlDatabasePool(_configuration, _environment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,15 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Redis.OM;
|
|
||||||
|
|
||||||
namespace CodeLiturgy.Views;
|
namespace CodeLiturgy.Views;
|
||||||
|
|
||||||
public static class StartupExtensions
|
public static class StartupExtensions
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) =>
|
private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) =>
|
||||||
new(new Version(major, minor, build));
|
new(new Version(major, minor, build));
|
||||||
|
*/
|
||||||
|
|
||||||
private static string GetConnectionString(this IConfiguration configurationRoot, string db)
|
private static string GetConnectionString(this IConfiguration configurationRoot, string db)
|
||||||
{
|
{
|
||||||
|
@ -45,14 +46,6 @@ public static class StartupExtensions
|
||||||
internal static IServiceCollection AddAuthServerServices(this IServiceCollection services,
|
internal static IServiceCollection AddAuthServerServices(this IServiceCollection services,
|
||||||
IConfiguration configuration, IWebHostEnvironment environment)
|
IConfiguration configuration, IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
var connectionString = configuration.GetConnectionString("Redis");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(connectionString))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Redis connection string is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
services.AddSession(options =>
|
services.AddSession(options =>
|
||||||
{
|
{
|
||||||
options.Cookie.Domain = SessionConstants.CookieDomain;
|
options.Cookie.Domain = SessionConstants.CookieDomain;
|
||||||
|
@ -61,11 +54,8 @@ public static class StartupExtensions
|
||||||
});
|
});
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddSingleton(new RedisConnectionProvider(connectionString))
|
|
||||||
.AddScoped<IJwtTokenHandler, JwtTokenHandler>()
|
.AddScoped<IJwtTokenHandler, JwtTokenHandler>()
|
||||||
.AddScoped<IJwtFactory, JwtFactory>()
|
.AddScoped<IJwtFactory, JwtFactory>()
|
||||||
.AddHostedService<SessionManager>()
|
|
||||||
.AddSingleton<ISessionCache, SessionManager>()
|
|
||||||
.AddScoped<UserRepository>()
|
.AddScoped<UserRepository>()
|
||||||
.AddScoped<IUserManager, ApplicationUserManager>()
|
.AddScoped<IUserManager, ApplicationUserManager>()
|
||||||
.AddScoped<IAuthManager, AuthManager>()
|
.AddScoped<IAuthManager, AuthManager>()
|
||||||
|
@ -164,6 +154,7 @@ public static class StartupExtensions
|
||||||
/// <param name="optionsBuilder"></param>
|
/// <param name="optionsBuilder"></param>
|
||||||
/// <param name="configuration"></param>
|
/// <param name="configuration"></param>
|
||||||
/// <param name="environment"></param>
|
/// <param name="environment"></param>
|
||||||
|
/*
|
||||||
private static DbContextOptionsBuilder GetMySqlSettings(
|
private static DbContextOptionsBuilder GetMySqlSettings(
|
||||||
this DbContextOptionsBuilder optionsBuilder,
|
this DbContextOptionsBuilder optionsBuilder,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
|
@ -200,7 +191,9 @@ public static class StartupExtensions
|
||||||
|
|
||||||
return optionsBuilder;
|
return optionsBuilder;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setup database Contexts
|
/// Setup database Contexts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -208,15 +201,17 @@ public static class StartupExtensions
|
||||||
/// <param name="configuration"></param>
|
/// <param name="configuration"></param>
|
||||||
/// <param name="environment"></param>
|
/// <param name="environment"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection PrepareMySqlDatabasePool(this IServiceCollection serviceCollection,
|
public static IServiceCollection PreparePostgresqlDatabasePool(this IServiceCollection serviceCollection,
|
||||||
IConfiguration configuration, IWebHostEnvironment environment)
|
IConfiguration configuration, IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
return serviceCollection
|
return serviceCollection;
|
||||||
.AddDbContextPool<UserDbContext>(options =>
|
/*.AddDbContextPool<UserDbContext>(options =>
|
||||||
options.GetMySqlSettings(configuration, environment))
|
options.GetMySqlSettings(configuration, environment))
|
||||||
.AddDbContextPool<CountryDbContext>(options =>
|
.AddDbContextPool<CountryDbContext>(options =>
|
||||||
options.GetMySqlSettings(configuration, environment))
|
options.GetMySqlSettings(configuration, environment))
|
||||||
.AddDbContextPool<ApplicationUserDbContext>(options =>
|
.AddDbContextPool<ApplicationUserDbContext>(options =>
|
||||||
options.GetMySqlSettings(configuration, environment));
|
options.GetMySqlSettings(configuration, environment));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"rollForward": "latestMajor",
|
||||||
|
"allowPrerelease": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue