Claim Logic

This commit is contained in:
Andre Beging
2022-04-11 15:51:11 +02:00
parent 1b2c6c4062
commit 5026196b46
9 changed files with 137 additions and 47 deletions

View File

@@ -98,6 +98,7 @@ namespace FoodsharingSiegen.Server.Auth
{
Name = "Andre",
Mail = "fs@beging.de",
GroupsList = new List<UserGroup> { UserGroup.Ambassador },
Type = UserType.Admin,
Created = DateTime.UtcNow,
EncryptedPassword = "qSIxTZo7J8M="
@@ -118,6 +119,14 @@ 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();
}

View File

@@ -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
/// <summary> LocalStorageService </summary>
private readonly LocalStorageService _localStorageService;
private readonly UserService _userService;
#endregion
#region Setup/Teardown
@@ -25,7 +28,12 @@ namespace FoodsharingSiegen.Server.Service
/// Constructor
/// </summary>
/// <param name="localStorageService"></param>
public TokenAuthStateProvider(LocalStorageService localStorageService) => _localStorageService = localStorageService;
/// <param name="userService"></param>
public TokenAuthStateProvider(LocalStorageService localStorageService, UserService userService)
{
_localStorageService = localStorageService;
_userService = userService;
}
#endregion
@@ -38,7 +46,11 @@ namespace FoodsharingSiegen.Server.Service
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var token = await _localStorageService.GetItem<string>(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)

View File

@@ -2,7 +2,7 @@ using FoodsharingSiegen.Contracts.Entity;
using FoodsharingSiegen.Server.Auth;
using Microsoft.AspNetCore.Components;
namespace FoodsharingSiegen.Server.Pages
namespace FoodsharingSiegen.Server.BaseClasses
{
/// <summary>
/// The fs base class (a. beging, 08.04.2022)

View File

@@ -29,6 +29,9 @@
[Parameter]
public int Minimum { get; set; } = 1;
[Parameter]
public bool AllowAddInteraction { get; set; }
private List<Interaction> Interactions => Prospect?.Interactions?.Where(x => x.Type == Type).ToList() ?? new List<Interaction>();
private bool Done => Interactions.Count >= Minimum;
@@ -62,7 +65,7 @@
<span>(<i>@interaction.Info</i>)</span>
}
@if (!Prospect.Complete || interaction.Type == InteractionType.Complete)
@if ((!Prospect.Complete || interaction.Type == InteractionType.Complete) && AllowAddInteraction)
{
<span>&nbsp;<a href=""><i class="fa-solid fa-square-xmark" @onclick="async () => await RemoveClick.InvokeAsync(interaction.Id)" @onclick:preventDefault></i></a></span>
}
@@ -71,7 +74,7 @@
}
}
@if (!Prospect.Complete && (Interactions.Count == 0 || Multiple))
@if (!Prospect.Complete && (Interactions.Count == 0 || Multiple) && AllowAddInteraction)
{
if (Multiple) ButtonText = "+";
<Button Size="Size.Small" Clicked="AddClick">@ButtonText</Button>

View File

@@ -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 @@
<InteractionRow
Prospect="Prospect"
Type="InteractionType.Welcome"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.WelcomeTeam)"
AddClick="() => AddInteraction(InteractionType.Welcome)"
RemoveClick="@RemoveInteraction"
Caption="Begrüßung"
@@ -28,6 +32,7 @@
<InteractionRow
Prospect="Prospect"
Type="InteractionType.EinAb"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.WelcomeTeam, UserGroup.StoreManager, UserGroup.Ambassador)"
AddClick="() => AddInteraction(InteractionType.EinAb)"
RemoveClick="@RemoveInteraction"
Caption="Einführungen"
@@ -40,6 +45,7 @@
<InteractionRow
Prospect="Prospect"
Type="InteractionType.IdCheck"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
AddClick="() => AddInteraction(InteractionType.IdCheck)"
RemoveClick="@RemoveInteraction"
Caption="Perso prüfen"
@@ -50,6 +56,7 @@
<InteractionRow
Prospect="Prospect"
Type="InteractionType.PdfPass"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
AddClick="() => AddInteraction(InteractionType.PdfPass)"
RemoveClick="@RemoveInteraction"
Caption="FS-Ausweis (digital)"
@@ -60,6 +67,7 @@
<InteractionRow
Prospect="Prospect"
Type="InteractionType.PrintPass"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
AddClick="() => AddInteraction(InteractionType.PrintPass)"
RemoveClick="@RemoveInteraction"
Caption="FS-Ausweis (print)"
@@ -69,6 +77,7 @@
<InteractionRow
Prospect="Prospect"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
Type="InteractionType.Verify"
AddClick="() => AddInteraction(InteractionType.Verify)"
RemoveClick="@RemoveInteraction"
@@ -79,6 +88,7 @@
<InteractionRow
Prospect="Prospect"
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
Type="InteractionType.Complete"
AddClick="() => AddInteraction(InteractionType.Complete)"
RemoveClick="@RemoveInteraction"

View File

@@ -1,16 +1,35 @@
using FoodsharingSiegen.Contracts;
using FoodsharingSiegen.Contracts;
using FoodsharingSiegen.Contracts.Entity;
using Microsoft.EntityFrameworkCore;
namespace FoodsharingSiegen.Server.Data.Service
{
/// <summary>
/// The user service class (a. beging, 11.04.2022)
/// </summary>
/// <seealso cref="ServiceBase"/>
public class UserService : ServiceBase
{
#region Setup/Teardown
/// <summary>
/// Initializes a new instance of the <see cref="UserService"/> class
/// </summary>
/// <param name="context">The context</param>
public UserService(FsContext context) : base(context)
{
}
#endregion
#region Public Method AddUserAsync
/// <summary>
/// Adds the user using the specified user (a. beging, 11.04.2022)
/// </summary>
/// <param name="user">The user</param>
/// <returns>A task containing an operation result of user</returns>
public async Task<OperationResult<User>> AddUserAsync(User user)
{
try
@@ -37,6 +56,61 @@ namespace FoodsharingSiegen.Server.Data.Service
}
#endregion
#region Public Method CheckForceLogout
/// <summary>
/// Checks the force logout using the specified user (a. beging, 11.04.2022)
/// </summary>
/// <param name="user">The user</param>
/// <returns>A task containing an operation result of bool</returns>
public async Task<OperationResult<bool>> CheckForceLogout(User user)
{
try
{
var anyR = await Context.Users.AnyAsync(x => x.Id == user.Id && x.ForceLogout);
return new OperationResult<bool>(anyR);
}
catch (Exception e)
{
return new OperationResult<bool>(e);
}
}
#endregion
#region Public Method GetUsersAsync
////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary> Gets users asynchronous. </summary>
///
/// <remarks> A Beging, 20.10.2021. </remarks>
///
/// <returns> An asynchronous result that yields the users. </returns>
////////////////////////////////////////////////////////////////////////////////////////////////////
public async Task<OperationResult<List<User>>> GetUsersAsync()
{
try
{
var users = await Context.Users.AsNoTracking().ToListAsync();
return new OperationResult<List<User>>(users);
}
catch (Exception e)
{
return new OperationResult<List<User>>(e);
}
}
#endregion
#region Public Method Update
/// <summary>
/// Updates the user (a. beging, 11.04.2022)
/// </summary>
/// <param name="user">The user</param>
/// <returns>A task containing the operation result</returns>
public async Task<OperationResult> Update(User user)
{
try
@@ -44,6 +118,14 @@ namespace FoodsharingSiegen.Server.Data.Service
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;
@@ -61,24 +143,6 @@ namespace FoodsharingSiegen.Server.Data.Service
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary> Gets users asynchronous. </summary>
///
/// <remarks> A Beging, 20.10.2021. </remarks>
///
/// <returns> An asynchronous result that yields the users. </returns>
////////////////////////////////////////////////////////////////////////////////////////////////////
public async Task<OperationResult<List<User>>> GetUsersAsync()
{
try
{
var users = await Context.Users.ToListAsync();
return new OperationResult<List<User>>(users);
}
catch (Exception e)
{
return new OperationResult<List<User>>(e);
}
}
#endregion
}
}

View File

@@ -5,6 +5,7 @@
@using FoodsharingSiegen.Server.Controls
@using FoodsharingSiegen.Contracts.Entity
@using FoodsharingSiegen.Contracts.Helper
@using FoodsharingSiegen.Server.BaseClasses
@inherits FsBase

View File

@@ -2,7 +2,7 @@
@page "/users"
@using FoodsharingSiegen.Contracts.Entity
@inherits FsBase
@inherits FoodsharingSiegen.Server.BaseClasses.FsBase
@code {

View File

@@ -20,8 +20,10 @@ namespace FoodsharingSiegen.Shared.Helper
/// <returns>The string</returns>
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,17 +59,6 @@ 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
{
@@ -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<User>(jsonObj.ToString());
user = JsonSerializer.Deserialize<User>(jsonObj.ToString()!);
if (user != null) user.Password = string.Empty;
}
return result.IsValid;
}
catch (Exception e)
catch (Exception)
{
return false;
}