From 5026196b46b03596b4e880695b6973dbbe60df93 Mon Sep 17 00:00:00 2001 From: Andre Beging Date: Mon, 11 Apr 2022 15:51:11 +0200 Subject: [PATCH] Claim Logic --- FoodsharingSiegen.Server/Auth/AuthService.cs | 11 +- .../Auth/TokenAuthStateProvider.cs | 16 ++- .../{Pages => BaseClasses}/FsBase.cs | 2 +- .../Controls/InteractionRow.razor | 7 +- .../Controls/ProspectContainer.razor | 10 ++ .../Data/Service/UserService.cs | 110 ++++++++++++++---- .../Pages/Prospects.razor | 1 + FoodsharingSiegen.Server/Pages/Users.razor | 2 +- FoodsharingSiegen.Shared/Helper/AuthHelper.cs | 25 ++-- 9 files changed, 137 insertions(+), 47 deletions(-) rename FoodsharingSiegen.Server/{Pages => BaseClasses}/FsBase.cs (95%) diff --git a/FoodsharingSiegen.Server/Auth/AuthService.cs b/FoodsharingSiegen.Server/Auth/AuthService.cs index 4409f92..3bbcccd 100644 --- a/FoodsharingSiegen.Server/Auth/AuthService.cs +++ b/FoodsharingSiegen.Server/Auth/AuthService.cs @@ -98,6 +98,7 @@ namespace FoodsharingSiegen.Server.Auth { Name = "Andre", Mail = "fs@beging.de", + GroupsList = new List { UserGroup.Ambassador }, Type = UserType.Admin, Created = DateTime.UtcNow, EncryptedPassword = "qSIxTZo7J8M=" @@ -117,7 +118,15 @@ namespace FoodsharingSiegen.Server.Auth { var serializedToken = AuthHelper.CreateToken(_user); await _localStorageService.SetItem(StorageKeys.TokenKey, serializedToken); - + + if (_user.ForceLogout) + { + _user.ForceLogout = false; + await Context.SaveChangesAsync(); + } + + Context.Entry(_user).State = EntityState.Detached; + return new OperationResult(); } diff --git a/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs b/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs index 2c84edf..cf1359c 100644 --- a/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs +++ b/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs @@ -1,6 +1,7 @@ using System.Security.Claims; using FoodsharingSiegen.Contracts; using FoodsharingSiegen.Server.Auth; +using FoodsharingSiegen.Server.Data.Service; using FoodsharingSiegen.Shared.Helper; using Microsoft.AspNetCore.Components.Authorization; @@ -17,6 +18,8 @@ namespace FoodsharingSiegen.Server.Service /// LocalStorageService private readonly LocalStorageService _localStorageService; + private readonly UserService _userService; + #endregion #region Setup/Teardown @@ -25,7 +28,12 @@ namespace FoodsharingSiegen.Server.Service /// Constructor /// /// - public TokenAuthStateProvider(LocalStorageService localStorageService) => _localStorageService = localStorageService; + /// + public TokenAuthStateProvider(LocalStorageService localStorageService, UserService userService) + { + _localStorageService = localStorageService; + _userService = userService; + } #endregion @@ -38,8 +46,12 @@ namespace FoodsharingSiegen.Server.Service public override async Task GetAuthenticationStateAsync() { var token = await _localStorageService.GetItem(StorageKeys.TokenKey); - var tokenValid = AuthHelper.ValidateToken(token, out _); + var tokenValid = AuthHelper.ValidateToken(token, out var user); + var checkR = await _userService.CheckForceLogout(user); + if (checkR.Success && checkR.Data) + tokenValid = false; + var identity = new ClaimsIdentity(); if (tokenValid) identity = new ClaimsIdentity(new[] diff --git a/FoodsharingSiegen.Server/Pages/FsBase.cs b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs similarity index 95% rename from FoodsharingSiegen.Server/Pages/FsBase.cs rename to FoodsharingSiegen.Server/BaseClasses/FsBase.cs index a291f96..771331b 100644 --- a/FoodsharingSiegen.Server/Pages/FsBase.cs +++ b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs @@ -2,7 +2,7 @@ using FoodsharingSiegen.Contracts.Entity; using FoodsharingSiegen.Server.Auth; using Microsoft.AspNetCore.Components; -namespace FoodsharingSiegen.Server.Pages +namespace FoodsharingSiegen.Server.BaseClasses { /// /// The fs base class (a. beging, 08.04.2022) diff --git a/FoodsharingSiegen.Server/Controls/InteractionRow.razor b/FoodsharingSiegen.Server/Controls/InteractionRow.razor index 13d405f..2123d94 100644 --- a/FoodsharingSiegen.Server/Controls/InteractionRow.razor +++ b/FoodsharingSiegen.Server/Controls/InteractionRow.razor @@ -28,6 +28,9 @@ [Parameter] public int Minimum { get; set; } = 1; + + [Parameter] + public bool AllowAddInteraction { get; set; } private List Interactions => Prospect?.Interactions?.Where(x => x.Type == Type).ToList() ?? new List(); @@ -62,7 +65,7 @@ (@interaction.Info) } - @if (!Prospect.Complete || interaction.Type == InteractionType.Complete) + @if ((!Prospect.Complete || interaction.Type == InteractionType.Complete) && AllowAddInteraction) {   } @@ -71,7 +74,7 @@ } } - @if (!Prospect.Complete && (Interactions.Count == 0 || Multiple)) + @if (!Prospect.Complete && (Interactions.Count == 0 || Multiple) && AllowAddInteraction) { if (Multiple) ButtonText = "+"; diff --git a/FoodsharingSiegen.Server/Controls/ProspectContainer.razor b/FoodsharingSiegen.Server/Controls/ProspectContainer.razor index d2cbe6b..a4c3e1c 100644 --- a/FoodsharingSiegen.Server/Controls/ProspectContainer.razor +++ b/FoodsharingSiegen.Server/Controls/ProspectContainer.razor @@ -1,4 +1,7 @@ @using FoodsharingSiegen.Contracts.Entity +@using FoodsharingSiegen.Contracts.Helper +@using FoodsharingSiegen.Server.BaseClasses +@inherits FsBase @{ var divClass = "pc-main"; @@ -18,6 +21,7 @@ + /// The user service class (a. beging, 11.04.2022) + /// + /// public class UserService : ServiceBase { + #region Setup/Teardown + + /// + /// Initializes a new instance of the class + /// + /// The context public UserService(FsContext context) : base(context) { } + #endregion + + #region Public Method AddUserAsync + + /// + /// Adds the user using the specified user (a. beging, 11.04.2022) + /// + /// The user + /// A task containing an operation result of user public async Task> AddUserAsync(User user) { try @@ -36,14 +55,77 @@ namespace FoodsharingSiegen.Server.Data.Service } } - + + #endregion + + #region Public Method CheckForceLogout + + /// + /// Checks the force logout using the specified user (a. beging, 11.04.2022) + /// + /// The user + /// A task containing an operation result of bool + public async Task> CheckForceLogout(User user) + { + try + { + var anyR = await Context.Users.AnyAsync(x => x.Id == user.Id && x.ForceLogout); + return new OperationResult(anyR); + } + catch (Exception e) + { + return new OperationResult(e); + } + } + + #endregion + + #region Public Method GetUsersAsync + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Gets users asynchronous. + /// + /// A Beging, 20.10.2021. + /// + /// An asynchronous result that yields the users. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public async Task>> GetUsersAsync() + { + try + { + var users = await Context.Users.AsNoTracking().ToListAsync(); + return new OperationResult>(users); + } + catch (Exception e) + { + return new OperationResult>(e); + } + } + + #endregion + + #region Public Method Update + + /// + /// Updates the user (a. beging, 11.04.2022) + /// + /// The user + /// A task containing the operation result public async Task Update(User user) { try { var entityUser = await Context.Users.FirstOrDefaultAsync(x => x.Id == user.Id); if (entityUser == null) return new OperationResult(new Exception("User not found")); - + + if (entityUser.Mail != user.Mail || + entityUser.Verified != user.Verified || + entityUser.Type != user.Type || + entityUser.Groups != user.Groups) + { + entityUser.ForceLogout = true; + } + entityUser.Mail = user.Mail; entityUser.Name = user.Name; entityUser.Type = user.Type; @@ -60,25 +142,7 @@ namespace FoodsharingSiegen.Server.Data.Service return new OperationResult(e); } } - - //////////////////////////////////////////////////////////////////////////////////////////////////// - /// Gets users asynchronous. - /// - /// A Beging, 20.10.2021. - /// - /// An asynchronous result that yields the users. - //////////////////////////////////////////////////////////////////////////////////////////////////// - public async Task>> GetUsersAsync() - { - try - { - var users = await Context.Users.ToListAsync(); - return new OperationResult>(users); - } - catch (Exception e) - { - return new OperationResult>(e); - } - } + + #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/Prospects.razor b/FoodsharingSiegen.Server/Pages/Prospects.razor index 2df9f58..7d834a8 100644 --- a/FoodsharingSiegen.Server/Pages/Prospects.razor +++ b/FoodsharingSiegen.Server/Pages/Prospects.razor @@ -5,6 +5,7 @@ @using FoodsharingSiegen.Server.Controls @using FoodsharingSiegen.Contracts.Entity @using FoodsharingSiegen.Contracts.Helper +@using FoodsharingSiegen.Server.BaseClasses @inherits FsBase diff --git a/FoodsharingSiegen.Server/Pages/Users.razor b/FoodsharingSiegen.Server/Pages/Users.razor index e545426..9d5ebd4 100644 --- a/FoodsharingSiegen.Server/Pages/Users.razor +++ b/FoodsharingSiegen.Server/Pages/Users.razor @@ -2,7 +2,7 @@ @page "/users" @using FoodsharingSiegen.Contracts.Entity -@inherits FsBase +@inherits FoodsharingSiegen.Server.BaseClasses.FsBase @code { diff --git a/FoodsharingSiegen.Shared/Helper/AuthHelper.cs b/FoodsharingSiegen.Shared/Helper/AuthHelper.cs index ceed536..3bb16b2 100644 --- a/FoodsharingSiegen.Shared/Helper/AuthHelper.cs +++ b/FoodsharingSiegen.Shared/Helper/AuthHelper.cs @@ -20,8 +20,10 @@ namespace FoodsharingSiegen.Shared.Helper /// The string public static string CreateToken(User user) { - user.Password = ""; - var serializedUser = JsonSerializer.Serialize(user); + var userClone = user.Clone(); + + userClone.Password = ""; + var serializedUser = JsonSerializer.Serialize(userClone); var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor @@ -57,18 +59,7 @@ namespace FoodsharingSiegen.Shared.Helper try { var tokenHandler = new JwtSecurityTokenHandler(); - tokenHandler.ValidateToken(token, new TokenValidationParameters - { - ValidateIssuerSigningKey = true, - IssuerSigningKey = Cryptor.GetSigningKey(), - - ValidateAudience = true, - ValidAudience = Audience, - - ValidateIssuer = true, - ValidIssuer = Issuer - }, out var stuff); - + var result = tokenHandler.ValidateTokenAsync(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, @@ -81,15 +72,15 @@ namespace FoodsharingSiegen.Shared.Helper ValidIssuer = Issuer }).Result; - if (result.Claims.TryGetValue(ClaimTypes.UserData, out var jsonObj)) + if (result.Claims.TryGetValue(ClaimTypes.UserData, out var jsonObj) && jsonObj != null) { - user = JsonSerializer.Deserialize(jsonObj.ToString()); + user = JsonSerializer.Deserialize(jsonObj.ToString()!); if (user != null) user.Password = string.Empty; } return result.IsValid; } - catch (Exception e) + catch (Exception) { return false; }