mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Added cacheing to Client Store, and Management API
This commit is contained in:
parent
b5c02f7640
commit
fc86f237fb
@ -14,10 +14,13 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Internal;
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Teknik.Configuration;
|
using Teknik.Configuration;
|
||||||
using Teknik.IdentityServer.Models;
|
using Teknik.IdentityServer.Models;
|
||||||
using Teknik.IdentityServer.Models.Manage;
|
using Teknik.IdentityServer.Models.Manage;
|
||||||
|
using Teknik.IdentityServer.Services;
|
||||||
using Teknik.Logging;
|
using Teknik.Logging;
|
||||||
using Teknik.Utilities;
|
using Teknik.Utilities;
|
||||||
|
|
||||||
@ -28,17 +31,22 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class ManageController : DefaultController
|
public class ManageController : DefaultController
|
||||||
{
|
{
|
||||||
|
private const string _UserInfoCacheKey = "UserInfo";
|
||||||
|
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
public ManageController(
|
public ManageController(
|
||||||
ILogger<Logger> logger,
|
ILogger<Logger> logger,
|
||||||
Config config,
|
Config config,
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
SignInManager<ApplicationUser> signInManager) : base(logger, config)
|
SignInManager<ApplicationUser> signInManager,
|
||||||
|
IMemoryCache cache) : base(logger, config)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -91,7 +99,11 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
|
|
||||||
var result = await _userManager.DeleteAsync(foundUser);
|
var result = await _userManager.DeleteAsync(foundUser);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return new JsonResult(new { success = false, message = "Unable to delete user.", identityErrors = result.Errors });
|
return new JsonResult(new { success = false, message = "Unable to delete user.", identityErrors = result.Errors });
|
||||||
}
|
}
|
||||||
@ -105,7 +117,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(username))
|
if (string.IsNullOrEmpty(username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(username);
|
var foundUser = await GetCachedUser(username);
|
||||||
return new JsonResult(new { success = true, data = foundUser != null });
|
return new JsonResult(new { success = true, data = foundUser != null });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,12 +127,11 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(username))
|
if (string.IsNullOrEmpty(username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(username);
|
var foundUser = await GetCachedUser(username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
return new JsonResult(new { success = true, data = foundUser.ToJson() });
|
return new JsonResult(new { success = true, data = foundUser.ToJson() });
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonResult(new { success = false, message = "User does not exist." });
|
return new JsonResult(new { success = false, message = "User does not exist." });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +143,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Password))
|
if (string.IsNullOrEmpty(model.Password))
|
||||||
return new JsonResult(new { success = false, message = "Password is required" });
|
return new JsonResult(new { success = false, message = "Password is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
bool valid = await _userManager.CheckPasswordAsync(foundUser, model.Password);
|
bool valid = await _userManager.CheckPasswordAsync(foundUser, model.Password);
|
||||||
@ -148,7 +159,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
string token = await _userManager.GeneratePasswordResetTokenAsync(foundUser);
|
string token = await _userManager.GeneratePasswordResetTokenAsync(foundUser);
|
||||||
@ -168,7 +179,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Password))
|
if (string.IsNullOrEmpty(model.Password))
|
||||||
return new JsonResult(new { success = false, message = "Password is required" });
|
return new JsonResult(new { success = false, message = "Password is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
var result = await _userManager.ResetPasswordAsync(foundUser, model.Token, model.Password);
|
var result = await _userManager.ResetPasswordAsync(foundUser, model.Token, model.Password);
|
||||||
@ -191,7 +202,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.NewPassword))
|
if (string.IsNullOrEmpty(model.NewPassword))
|
||||||
return new JsonResult(new { success = false, message = "New Password is required" });
|
return new JsonResult(new { success = false, message = "New Password is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
var result = await _userManager.ChangePasswordAsync(foundUser, model.CurrentPassword, model.NewPassword);
|
var result = await _userManager.ChangePasswordAsync(foundUser, model.CurrentPassword, model.NewPassword);
|
||||||
@ -210,12 +221,15 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
var result = await _userManager.SetEmailAsync(foundUser, model.Email);
|
var result = await _userManager.SetEmailAsync(foundUser, model.Email);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
var token = await _userManager.GenerateEmailConfirmationTokenAsync(foundUser);
|
var token = await _userManager.GenerateEmailConfirmationTokenAsync(foundUser);
|
||||||
return new JsonResult(new { success = true, data = token });
|
return new JsonResult(new { success = true, data = token });
|
||||||
}
|
}
|
||||||
@ -234,9 +248,12 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Token))
|
if (string.IsNullOrEmpty(model.Token))
|
||||||
return new JsonResult(new { success = false, message = "Token is required" });
|
return new JsonResult(new { success = false, message = "Token is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
var result = await _userManager.ConfirmEmailAsync(foundUser, model.Token);
|
var result = await _userManager.ConfirmEmailAsync(foundUser, model.Token);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
@ -253,14 +270,19 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
foundUser.AccountStatus = model.AccountStatus;
|
foundUser.AccountStatus = model.AccountStatus;
|
||||||
|
|
||||||
var result = await _userManager.UpdateAsync(foundUser);
|
var result = await _userManager.UpdateAsync(foundUser);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return new JsonResult(new { success = false, message = "Unable to update account status.", identityErrors = result.Errors });
|
return new JsonResult(new { success = false, message = "Unable to update account status.", identityErrors = result.Errors });
|
||||||
}
|
}
|
||||||
@ -274,14 +296,19 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
foundUser.AccountType = model.AccountType;
|
foundUser.AccountType = model.AccountType;
|
||||||
|
|
||||||
var result = await _userManager.UpdateAsync(foundUser);
|
var result = await _userManager.UpdateAsync(foundUser);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return new JsonResult(new { success = false, message = "Unable to update account type.", identityErrors = result.Errors });
|
return new JsonResult(new { success = false, message = "Unable to update account type.", identityErrors = result.Errors });
|
||||||
}
|
}
|
||||||
@ -295,14 +322,19 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
foundUser.PGPPublicKey = model.PGPPublicKey;
|
foundUser.PGPPublicKey = model.PGPPublicKey;
|
||||||
|
|
||||||
var result = await _userManager.UpdateAsync(foundUser);
|
var result = await _userManager.UpdateAsync(foundUser);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return new JsonResult(new { success = false, message = "Unable to update pgp public key.", identityErrors = result.Errors });
|
return new JsonResult(new { success = false, message = "Unable to update pgp public key.", identityErrors = result.Errors });
|
||||||
}
|
}
|
||||||
@ -316,7 +348,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(username))
|
if (string.IsNullOrEmpty(username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(username);
|
var foundUser = await GetCachedUser(username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
|
string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
|
||||||
@ -333,9 +365,12 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
await _userManager.ResetAuthenticatorKeyAsync(foundUser);
|
await _userManager.ResetAuthenticatorKeyAsync(foundUser);
|
||||||
string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
|
string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
|
||||||
|
|
||||||
@ -353,7 +388,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Code))
|
if (string.IsNullOrEmpty(model.Code))
|
||||||
return new JsonResult(new { success = false, message = "Code is required" });
|
return new JsonResult(new { success = false, message = "Code is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
// Strip spaces and hypens
|
// Strip spaces and hypens
|
||||||
@ -367,6 +402,9 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, true);
|
var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, true);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
|
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
|
||||||
return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
|
return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
|
||||||
}
|
}
|
||||||
@ -386,12 +424,17 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, false);
|
var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, false);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
return new JsonResult(new { success = true });
|
return new JsonResult(new { success = true });
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return new JsonResult(new { success = false, message = "Unable to disable Two-Factor Authentication.", identityErrors = result.Errors });
|
return new JsonResult(new { success = false, message = "Unable to disable Two-Factor Authentication.", identityErrors = result.Errors });
|
||||||
}
|
}
|
||||||
@ -405,11 +448,14 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
if (string.IsNullOrEmpty(model.Username))
|
if (string.IsNullOrEmpty(model.Username))
|
||||||
return new JsonResult(new { success = false, message = "Username is required" });
|
return new JsonResult(new { success = false, message = "Username is required" });
|
||||||
|
|
||||||
var foundUser = await _userManager.FindByNameAsync(model.Username);
|
var foundUser = await GetCachedUser(model.Username);
|
||||||
if (foundUser != null)
|
if (foundUser != null)
|
||||||
{
|
{
|
||||||
if (foundUser.TwoFactorEnabled)
|
if (foundUser.TwoFactorEnabled)
|
||||||
{
|
{
|
||||||
|
// Remove the UserInfo Cache
|
||||||
|
RemoveCachedUser(model.Username);
|
||||||
|
|
||||||
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
|
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
|
||||||
|
|
||||||
return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
|
return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
|
||||||
@ -607,5 +653,34 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
|
|
||||||
return result.ToString().ToLowerInvariant();
|
return result.ToString().ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<ApplicationUser> GetCachedUser(string username)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(username))
|
||||||
|
throw new ArgumentNullException("username");
|
||||||
|
|
||||||
|
// Check the cache
|
||||||
|
string cacheKey = _UserInfoCacheKey + username;
|
||||||
|
ApplicationUser foundUser;
|
||||||
|
if (!_cache.TryGetValue(cacheKey, out foundUser))
|
||||||
|
{
|
||||||
|
foundUser = await _userManager.FindByNameAsync(username);
|
||||||
|
if (foundUser != null)
|
||||||
|
{
|
||||||
|
_cache.AddToCache(cacheKey, foundUser, new TimeSpan(1, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveCachedUser(string username)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(username))
|
||||||
|
throw new ArgumentNullException("username");
|
||||||
|
|
||||||
|
string cacheKey = _UserInfoCacheKey + username;
|
||||||
|
_cache.Remove(cacheKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
244
IdentityServer/Data/Migrations/ApplicationDb/20190129061223_UserEditDate.Designer.cs
generated
Normal file
244
IdentityServer/Data/Migrations/ApplicationDb/20190129061223_UserEditDate.Designer.cs
generated
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Teknik.IdentityServer;
|
||||||
|
|
||||||
|
namespace Teknik.IdentityServer.Data.Migrations.ApplicationDb
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20190129061223_UserEditDate")]
|
||||||
|
partial class UserEditDate
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasName("RoleNameIndex")
|
||||||
|
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("Value");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Teknik.IdentityServer.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount");
|
||||||
|
|
||||||
|
b.Property<int>("AccountStatus");
|
||||||
|
|
||||||
|
b.Property<int>("AccountType");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationDate");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastEdit");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeen");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<string>("PGPPublicKey");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasName("UserNameIndex")
|
||||||
|
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Teknik.IdentityServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Teknik.IdentityServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("Teknik.IdentityServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Teknik.IdentityServer.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Teknik.IdentityServer.Data.Migrations.ApplicationDb
|
||||||
|
{
|
||||||
|
public partial class UserEditDate : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastEdit",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastEdit",
|
||||||
|
table: "AspNetUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ namespace Teknik.IdentityServer.Data.Migrations.ApplicationDb
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "2.2.0-preview2-35157")
|
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
@ -150,6 +150,8 @@ namespace Teknik.IdentityServer.Data.Migrations.ApplicationDb
|
|||||||
|
|
||||||
b.Property<bool>("EmailConfirmed");
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastEdit");
|
||||||
|
|
||||||
b.Property<DateTime>("LastSeen");
|
b.Property<DateTime>("LastSeen");
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled");
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
@ -21,6 +21,8 @@ namespace Teknik.IdentityServer.Models
|
|||||||
|
|
||||||
public string PGPPublicKey { get; set; }
|
public string PGPPublicKey { get; set; }
|
||||||
|
|
||||||
|
public DateTime LastEdit { get; set; }
|
||||||
|
|
||||||
public ApplicationUser() : base()
|
public ApplicationUser() : base()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
@ -35,6 +37,7 @@ namespace Teknik.IdentityServer.Models
|
|||||||
{
|
{
|
||||||
CreationDate = DateTime.Now;
|
CreationDate = DateTime.Now;
|
||||||
LastSeen = DateTime.Now;
|
LastSeen = DateTime.Now;
|
||||||
|
LastEdit = DateTime.Now;
|
||||||
AccountType = AccountType.Basic;
|
AccountType = AccountType.Basic;
|
||||||
AccountStatus = AccountStatus.Active;
|
AccountStatus = AccountStatus.Active;
|
||||||
PGPPublicKey = null;
|
PGPPublicKey = null;
|
||||||
@ -46,6 +49,7 @@ namespace Teknik.IdentityServer.Models
|
|||||||
claims.Add(new Claim("username", UserName));
|
claims.Add(new Claim("username", UserName));
|
||||||
claims.Add(new Claim("creation-date", CreationDate.ToString("o")));
|
claims.Add(new Claim("creation-date", CreationDate.ToString("o")));
|
||||||
claims.Add(new Claim("last-seen", LastSeen.ToString("o")));
|
claims.Add(new Claim("last-seen", LastSeen.ToString("o")));
|
||||||
|
claims.Add(new Claim("last-edit", LastEdit.ToString("o")));
|
||||||
claims.Add(new Claim("account-type", AccountType.ToString()));
|
claims.Add(new Claim("account-type", AccountType.ToString()));
|
||||||
claims.Add(new Claim("account-status", AccountStatus.ToString()));
|
claims.Add(new Claim("account-status", AccountStatus.ToString()));
|
||||||
claims.Add(new Claim("recovery-email", Email ?? string.Empty));
|
claims.Add(new Claim("recovery-email", Email ?? string.Empty));
|
||||||
@ -62,6 +66,7 @@ namespace Teknik.IdentityServer.Models
|
|||||||
new JProperty("username", UserName),
|
new JProperty("username", UserName),
|
||||||
new JProperty("creation-date", CreationDate),
|
new JProperty("creation-date", CreationDate),
|
||||||
new JProperty("last-seen", LastSeen),
|
new JProperty("last-seen", LastSeen),
|
||||||
|
new JProperty("last-edit", LastEdit),
|
||||||
new JProperty("account-type", AccountType),
|
new JProperty("account-type", AccountType),
|
||||||
new JProperty("account-status", AccountStatus),
|
new JProperty("account-status", AccountStatus),
|
||||||
new JProperty("recovery-email", Email),
|
new JProperty("recovery-email", Email),
|
||||||
|
@ -23,8 +23,7 @@ using Teknik.Logging;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Teknik.IdentityServer.Models;
|
using Teknik.IdentityServer.Models;
|
||||||
using IdentityServer4.Services;
|
using IdentityServer4.Services;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Teknik.Utilities;
|
|
||||||
|
|
||||||
namespace Teknik.IdentityServer
|
namespace Teknik.IdentityServer
|
||||||
{
|
{
|
||||||
@ -128,6 +127,7 @@ namespace Teknik.IdentityServer
|
|||||||
options.Cors.CorsPaths.Add(new PathString("/connect/endsession"));
|
options.Cors.CorsPaths.Add(new PathString("/connect/endsession"));
|
||||||
options.Cors.CorsPaths.Add(new PathString("/connect/checksession"));
|
options.Cors.CorsPaths.Add(new PathString("/connect/checksession"));
|
||||||
options.Cors.CorsPaths.Add(new PathString("/connect/introspect"));
|
options.Cors.CorsPaths.Add(new PathString("/connect/introspect"));
|
||||||
|
options.Caching.ClientStoreExpiration = TimeSpan.FromHours(1);
|
||||||
})
|
})
|
||||||
.AddOperationalStore(options =>
|
.AddOperationalStore(options =>
|
||||||
options.ConfigureDbContext = builder =>
|
options.ConfigureDbContext = builder =>
|
||||||
@ -135,6 +135,7 @@ namespace Teknik.IdentityServer
|
|||||||
.AddConfigurationStore(options =>
|
.AddConfigurationStore(options =>
|
||||||
options.ConfigureDbContext = builder =>
|
options.ConfigureDbContext = builder =>
|
||||||
builder.UseSqlServer(config.DbConnection, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
|
builder.UseSqlServer(config.DbConnection, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
|
||||||
|
.AddConfigurationStoreCache()
|
||||||
.AddAspNetIdentity<ApplicationUser>()
|
.AddAspNetIdentity<ApplicationUser>()
|
||||||
.AddRedirectUriValidator<TeknikRedirectUriValidator>()
|
.AddRedirectUriValidator<TeknikRedirectUriValidator>()
|
||||||
.AddDeveloperSigningCredential();
|
.AddDeveloperSigningCredential();
|
||||||
|
@ -25,4 +25,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<bundle src="js/userInfo.min.js" append-version="true"></bundle>
|
<bundle src="js/userSearch.min.js" append-version="true"></bundle>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
{
|
{
|
||||||
"outputFileName": "./wwwroot/js/userSearch.min.js",
|
"outputFileName": "./wwwroot/js/userSearch.min.js",
|
||||||
"inputFiles": [
|
"inputFiles": [
|
||||||
"./wwwroot/js/app/Admin/UserInfo.js"
|
"./wwwroot/js/app/Admin/UserSearch.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
33
Utilities/MemoryCacheHelper.cs
Normal file
33
Utilities/MemoryCacheHelper.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace Teknik.Utilities
|
||||||
|
{
|
||||||
|
public static class MemoryCacheHelper
|
||||||
|
{
|
||||||
|
public static bool GetCacheValue<T>(this IMemoryCache cache, string key, out T value)
|
||||||
|
{
|
||||||
|
return cache.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetCacheValue(this IMemoryCache cache, string key, out object value)
|
||||||
|
{
|
||||||
|
return cache.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddToCache(this IMemoryCache cache, string key, object value, TimeSpan expiration)
|
||||||
|
{
|
||||||
|
var cacheOptions = new MemoryCacheEntryOptions()
|
||||||
|
.SetAbsoluteExpiration(expiration);
|
||||||
|
|
||||||
|
cache.AddToCache(key, value, cacheOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddToCache(this IMemoryCache cache, string key, object value, MemoryCacheEntryOptions options)
|
||||||
|
{
|
||||||
|
cache.Set(key, value, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user