Claim Logic
This commit is contained in:
@@ -98,6 +98,7 @@ namespace FoodsharingSiegen.Server.Auth
|
|||||||
{
|
{
|
||||||
Name = "Andre",
|
Name = "Andre",
|
||||||
Mail = "fs@beging.de",
|
Mail = "fs@beging.de",
|
||||||
|
GroupsList = new List<UserGroup> { UserGroup.Ambassador },
|
||||||
Type = UserType.Admin,
|
Type = UserType.Admin,
|
||||||
Created = DateTime.UtcNow,
|
Created = DateTime.UtcNow,
|
||||||
EncryptedPassword = "qSIxTZo7J8M="
|
EncryptedPassword = "qSIxTZo7J8M="
|
||||||
@@ -117,7 +118,15 @@ namespace FoodsharingSiegen.Server.Auth
|
|||||||
{
|
{
|
||||||
var serializedToken = AuthHelper.CreateToken(_user);
|
var serializedToken = AuthHelper.CreateToken(_user);
|
||||||
await _localStorageService.SetItem(StorageKeys.TokenKey, serializedToken);
|
await _localStorageService.SetItem(StorageKeys.TokenKey, serializedToken);
|
||||||
|
|
||||||
|
if (_user.ForceLogout)
|
||||||
|
{
|
||||||
|
_user.ForceLogout = false;
|
||||||
|
await Context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.Entry(_user).State = EntityState.Detached;
|
||||||
|
|
||||||
return new OperationResult();
|
return new OperationResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using FoodsharingSiegen.Contracts;
|
using FoodsharingSiegen.Contracts;
|
||||||
using FoodsharingSiegen.Server.Auth;
|
using FoodsharingSiegen.Server.Auth;
|
||||||
|
using FoodsharingSiegen.Server.Data.Service;
|
||||||
using FoodsharingSiegen.Shared.Helper;
|
using FoodsharingSiegen.Shared.Helper;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
|
||||||
@@ -17,6 +18,8 @@ namespace FoodsharingSiegen.Server.Service
|
|||||||
/// <summary> LocalStorageService </summary>
|
/// <summary> LocalStorageService </summary>
|
||||||
private readonly LocalStorageService _localStorageService;
|
private readonly LocalStorageService _localStorageService;
|
||||||
|
|
||||||
|
private readonly UserService _userService;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Setup/Teardown
|
#region Setup/Teardown
|
||||||
@@ -25,7 +28,12 @@ namespace FoodsharingSiegen.Server.Service
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="localStorageService"></param>
|
/// <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
|
#endregion
|
||||||
|
|
||||||
@@ -38,8 +46,12 @@ namespace FoodsharingSiegen.Server.Service
|
|||||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
{
|
{
|
||||||
var token = await _localStorageService.GetItem<string>(StorageKeys.TokenKey);
|
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();
|
var identity = new ClaimsIdentity();
|
||||||
if (tokenValid)
|
if (tokenValid)
|
||||||
identity = new ClaimsIdentity(new[]
|
identity = new ClaimsIdentity(new[]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using FoodsharingSiegen.Contracts.Entity;
|
|||||||
using FoodsharingSiegen.Server.Auth;
|
using FoodsharingSiegen.Server.Auth;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace FoodsharingSiegen.Server.Pages
|
namespace FoodsharingSiegen.Server.BaseClasses
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The fs base class (a. beging, 08.04.2022)
|
/// The fs base class (a. beging, 08.04.2022)
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int Minimum { get; set; } = 1;
|
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 List<Interaction> Interactions => Prospect?.Interactions?.Where(x => x.Type == Type).ToList() ?? new List<Interaction>();
|
||||||
|
|
||||||
@@ -62,7 +65,7 @@
|
|||||||
<span>(<i>@interaction.Info</i>)</span>
|
<span>(<i>@interaction.Info</i>)</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (!Prospect.Complete || interaction.Type == InteractionType.Complete)
|
@if ((!Prospect.Complete || interaction.Type == InteractionType.Complete) && AllowAddInteraction)
|
||||||
{
|
{
|
||||||
<span> <a href=""><i class="fa-solid fa-square-xmark" @onclick="async () => await RemoveClick.InvokeAsync(interaction.Id)" @onclick:preventDefault></i></a></span>
|
<span> <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 = "+";
|
if (Multiple) ButtonText = "+";
|
||||||
<Button Size="Size.Small" Clicked="AddClick">@ButtonText</Button>
|
<Button Size="Size.Small" Clicked="AddClick">@ButtonText</Button>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
@using FoodsharingSiegen.Contracts.Entity
|
@using FoodsharingSiegen.Contracts.Entity
|
||||||
|
@using FoodsharingSiegen.Contracts.Helper
|
||||||
|
@using FoodsharingSiegen.Server.BaseClasses
|
||||||
|
@inherits FsBase
|
||||||
|
|
||||||
@{
|
@{
|
||||||
var divClass = "pc-main";
|
var divClass = "pc-main";
|
||||||
@@ -18,6 +21,7 @@
|
|||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
Type="InteractionType.Welcome"
|
Type="InteractionType.Welcome"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.WelcomeTeam)"
|
||||||
AddClick="() => AddInteraction(InteractionType.Welcome)"
|
AddClick="() => AddInteraction(InteractionType.Welcome)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
Caption="Begrüßung"
|
Caption="Begrüßung"
|
||||||
@@ -28,6 +32,7 @@
|
|||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
Type="InteractionType.EinAb"
|
Type="InteractionType.EinAb"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.WelcomeTeam, UserGroup.StoreManager, UserGroup.Ambassador)"
|
||||||
AddClick="() => AddInteraction(InteractionType.EinAb)"
|
AddClick="() => AddInteraction(InteractionType.EinAb)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
Caption="Einführungen"
|
Caption="Einführungen"
|
||||||
@@ -40,6 +45,7 @@
|
|||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
Type="InteractionType.IdCheck"
|
Type="InteractionType.IdCheck"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
|
||||||
AddClick="() => AddInteraction(InteractionType.IdCheck)"
|
AddClick="() => AddInteraction(InteractionType.IdCheck)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
Caption="Perso prüfen"
|
Caption="Perso prüfen"
|
||||||
@@ -50,6 +56,7 @@
|
|||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
Type="InteractionType.PdfPass"
|
Type="InteractionType.PdfPass"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
|
||||||
AddClick="() => AddInteraction(InteractionType.PdfPass)"
|
AddClick="() => AddInteraction(InteractionType.PdfPass)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
Caption="FS-Ausweis (digital)"
|
Caption="FS-Ausweis (digital)"
|
||||||
@@ -60,6 +67,7 @@
|
|||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
Type="InteractionType.PrintPass"
|
Type="InteractionType.PrintPass"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
|
||||||
AddClick="() => AddInteraction(InteractionType.PrintPass)"
|
AddClick="() => AddInteraction(InteractionType.PrintPass)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
Caption="FS-Ausweis (print)"
|
Caption="FS-Ausweis (print)"
|
||||||
@@ -69,6 +77,7 @@
|
|||||||
|
|
||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
|
||||||
Type="InteractionType.Verify"
|
Type="InteractionType.Verify"
|
||||||
AddClick="() => AddInteraction(InteractionType.Verify)"
|
AddClick="() => AddInteraction(InteractionType.Verify)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
@@ -79,6 +88,7 @@
|
|||||||
|
|
||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
|
AllowAddInteraction="@CurrentUser.IsInGroup(UserGroup.Ambassador)"
|
||||||
Type="InteractionType.Complete"
|
Type="InteractionType.Complete"
|
||||||
AddClick="() => AddInteraction(InteractionType.Complete)"
|
AddClick="() => AddInteraction(InteractionType.Complete)"
|
||||||
RemoveClick="@RemoveInteraction"
|
RemoveClick="@RemoveInteraction"
|
||||||
|
|||||||
@@ -1,16 +1,35 @@
|
|||||||
using FoodsharingSiegen.Contracts;
|
using FoodsharingSiegen.Contracts;
|
||||||
using FoodsharingSiegen.Contracts.Entity;
|
using FoodsharingSiegen.Contracts.Entity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace FoodsharingSiegen.Server.Data.Service
|
namespace FoodsharingSiegen.Server.Data.Service
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user service class (a. beging, 11.04.2022)
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ServiceBase"/>
|
||||||
public class UserService : 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)
|
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)
|
public async Task<OperationResult<User>> AddUserAsync(User user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -36,14 +55,77 @@ 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)
|
public async Task<OperationResult> Update(User user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var entityUser = await Context.Users.FirstOrDefaultAsync(x => x.Id == user.Id);
|
var entityUser = await Context.Users.FirstOrDefaultAsync(x => x.Id == user.Id);
|
||||||
if (entityUser == null) return new OperationResult(new Exception("User not found"));
|
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.Mail = user.Mail;
|
||||||
entityUser.Name = user.Name;
|
entityUser.Name = user.Name;
|
||||||
entityUser.Type = user.Type;
|
entityUser.Type = user.Type;
|
||||||
@@ -60,25 +142,7 @@ namespace FoodsharingSiegen.Server.Data.Service
|
|||||||
return new OperationResult(e);
|
return new OperationResult(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
#endregion
|
||||||
/// <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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
@using FoodsharingSiegen.Server.Controls
|
@using FoodsharingSiegen.Server.Controls
|
||||||
@using FoodsharingSiegen.Contracts.Entity
|
@using FoodsharingSiegen.Contracts.Entity
|
||||||
@using FoodsharingSiegen.Contracts.Helper
|
@using FoodsharingSiegen.Contracts.Helper
|
||||||
|
@using FoodsharingSiegen.Server.BaseClasses
|
||||||
|
|
||||||
@inherits FsBase
|
@inherits FsBase
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@page "/users"
|
@page "/users"
|
||||||
@using FoodsharingSiegen.Contracts.Entity
|
@using FoodsharingSiegen.Contracts.Entity
|
||||||
|
|
||||||
@inherits FsBase
|
@inherits FoodsharingSiegen.Server.BaseClasses.FsBase
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ namespace FoodsharingSiegen.Shared.Helper
|
|||||||
/// <returns>The string</returns>
|
/// <returns>The string</returns>
|
||||||
public static string CreateToken(User user)
|
public static string CreateToken(User user)
|
||||||
{
|
{
|
||||||
user.Password = "";
|
var userClone = user.Clone();
|
||||||
var serializedUser = JsonSerializer.Serialize(user);
|
|
||||||
|
userClone.Password = "";
|
||||||
|
var serializedUser = JsonSerializer.Serialize(userClone);
|
||||||
|
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
var tokenDescriptor = new SecurityTokenDescriptor
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
@@ -57,18 +59,7 @@ namespace FoodsharingSiegen.Shared.Helper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
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
|
var result = tokenHandler.ValidateTokenAsync(token, new TokenValidationParameters
|
||||||
{
|
{
|
||||||
ValidateIssuerSigningKey = true,
|
ValidateIssuerSigningKey = true,
|
||||||
@@ -81,15 +72,15 @@ namespace FoodsharingSiegen.Shared.Helper
|
|||||||
ValidIssuer = Issuer
|
ValidIssuer = Issuer
|
||||||
}).Result;
|
}).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;
|
if (user != null) user.Password = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.IsValid;
|
return result.IsValid;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user