diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/App.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/App.razor
index cc3223e..8118d77 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/App.razor
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/App.razor
@@ -1,14 +1,18 @@
@using GameIdeas.BlazorApp.Layouts
+@using Microsoft.AspNetCore.Components.Authorization
+
+
+
+
+
+
+
+
+ Not found
+
+ Sorry, there's nothing at this address.
+
+
+
+
-
-
-
-
-
-
- Not found
-
- Sorry, there's nothing at this address.
-
-
-
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/GameHelper.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/GameHelper.cs
index 9673b84..181281d 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/GameHelper.cs
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/GameHelper.cs
@@ -1,12 +1,26 @@
using GameIdeas.Shared.Dto;
+using Microsoft.AspNetCore.Components.Authorization;
+using System.Security.Claims;
namespace GameIdeas.BlazorApp.Helpers;
public static class GameHelper
{
- public static void WriteTrackingDto(GameDetailDto game)
+ public static void WriteTrackingDto(GameDetailDto game, AuthenticationState authState)
{
- game.CreationUserId = 100000;
+ if (authState == null)
+ {
+ throw new ArgumentNullException(nameof(authState), "Authentication state missing");
+ }
+
+ var userId = authState.User.FindFirstValue(ClaimTypes.Sid);
+
+ if (userId == null)
+ {
+ throw new ArgumentNullException(nameof(authState), "user state missing");
+ }
+
+ game.CreationUserId = userId;
game.CreationDate = DateTime.Now;
}
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs
index 895fb72..9685dc5 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs
@@ -5,8 +5,10 @@ using GameIdeas.BlazorApp.Shared.Components.Select.Models;
using GameIdeas.BlazorApp.Shared.Components.Slider;
using GameIdeas.Shared.Dto;
using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
+using System.Security.Claims;
namespace GameIdeas.BlazorApp.Pages.Games.Components;
@@ -14,6 +16,7 @@ public partial class GameCreationForm
{
[Inject] private IJSRuntime Js { get; set; } = default!;
[Inject] private IGameGateway GameGateway { get; set; } = default!;
+ [Inject] private AuthenticationStateProvider AuthenticationState { get; set; } = default!;
[CascadingParameter] private Popup? Popup { get; set; }
[Parameter] public CategoriesDto? Categories { get; set; }
[Parameter] public EventCallback OnSubmit { get; set; }
@@ -33,7 +36,6 @@ public partial class GameCreationForm
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await Js.InvokeVoidAsync("resizeGameForm");
-
}
private void HandleOnCancel()
@@ -52,7 +54,9 @@ public partial class GameCreationForm
{
IsLoading = true;
- GameHelper.WriteTrackingDto(GameDto);
+ var authState = await AuthenticationState.GetAuthenticationStateAsync();
+ GameHelper.WriteTrackingDto(GameDto, authState);
+
var gameId = await GameGateway.CreateGame(GameDto);
if (gameId != 0)
@@ -68,6 +72,7 @@ public partial class GameCreationForm
finally
{
IsLoading = false;
+ StateHasChanged();
}
}
}
\ No newline at end of file
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor
index d62b74a..0516759 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor
@@ -4,6 +4,8 @@
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
@using GameIdeas.BlazorApp.Shared.Models
@using GameIdeas.Resources
+@using GameIdeas.Shared.Constants
+@using Microsoft.AspNetCore.Components.Authorization
@inherits ComponentBase
@@ -15,23 +17,26 @@
@ChildContent
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.css b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.css
index 0650995..4b6f742 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.css
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.css
@@ -29,15 +29,12 @@
align-items: flex-end;
}
-.add-container {
- margin-right: 40px;
-}
-
.add-buttons {
display: flex;
flex-direction: row;
background: var(--violet);
border-radius: var(--small-radius);
+ margin-right: 40px;
}
.button {
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/Component.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/Component.razor
deleted file mode 100644
index e69de29..0000000
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/UserMenu.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/UserMenu.razor
index b069564..49c6910 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/UserMenu.razor
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/User/UserMenu.razor
@@ -12,36 +12,34 @@
@if (ContentVisile)
{
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
}
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs
index f0c39ac..41c4cf0 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs
@@ -3,10 +3,15 @@ using System.Net.Http.Headers;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text;
+using Blazored.LocalStorage;
+using GameIdeas.Shared.Constants;
namespace GameIdeas.BlazorApp.Services;
-public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory) : IHttpClientService
+public class HttpClientService(
+ IHttpClientFactory httpClientFactory,
+ ILoggerFactory loggerFactory,
+ ILocalStorageService localStorage) : IHttpClientService
{
private readonly HttpClient httpClient = httpClientFactory.CreateClient("GameIdeas.WebAPI");
private readonly ILogger logger = loggerFactory.CreateLogger();
@@ -25,6 +30,8 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task PostAsync(string url, object data)
{
+ await SetAuthorizationHeader();
+
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(url, content);
@@ -32,8 +39,11 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
return await GetResultValue(response, ResourcesKey.ErrorWhenPostingData);
}
+
public async Task PutAsync(string url, object data)
{
+ await SetAuthorizationHeader();
+
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
var response = await httpClient.PutAsync(url, content);
@@ -43,6 +53,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task DeleteAsync(string? url)
{
+ await SetAuthorizationHeader();
var response = await httpClient.DeleteAsync(url);
return await GetResultValue(response, ResourcesKey.ErrorWhenDeletingData);
@@ -50,6 +61,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task FetchDataAsync(string? url)
{
+ await SetAuthorizationHeader();
var response = await httpClient.GetAsync(url);
return await GetResultValue(response, ResourcesKey.ErrorWhenFetchingData);
@@ -57,6 +69,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task FetchBytesAsync(string? url)
{
+ await SetAuthorizationHeader();
var response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
@@ -71,6 +84,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task FetchStreamAsync(string? url)
{
+ await SetAuthorizationHeader();
var response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
@@ -84,6 +98,8 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
public async Task PostFileAsync(string? url, Stream fileStream, string fileName, string contentType)
{
+ await SetAuthorizationHeader();
+
using var content = new MultipartFormDataContent();
var streamContent = new StreamContent(fileStream);
@@ -122,4 +138,11 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
throw new HttpRequestException(
$"{errorMessage} + StatusCode: {response.StatusCode} + Reason: {response.ReasonPhrase}");
}
+
+ private async Task SetAuthorizationHeader()
+ {
+ var token = await localStorage.GetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
+ httpClient.DefaultRequestHeaders.Authorization =
+ new AuthenticationHeaderValue("bearer", token);
+ }
}
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/JwtAuthenticationStateProvider.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/JwtAuthenticationStateProvider.cs
index 2417dac..6ea212f 100644
--- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/JwtAuthenticationStateProvider.cs
+++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/JwtAuthenticationStateProvider.cs
@@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
+using GameIdeas.Shared.Constants;
namespace GameIdeas.BlazorApp.Services;
@@ -9,7 +10,7 @@ public class JwtAuthenticationStateProvider(ILocalStorageService localStorage) :
{
public override async Task GetAuthenticationStateAsync()
{
- var savedToken = await localStorage.GetItemAsStringAsync("authToken");
+ var savedToken = await localStorage.GetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
if (!string.IsNullOrWhiteSpace(savedToken))
{
@@ -23,7 +24,7 @@ public class JwtAuthenticationStateProvider(ILocalStorageService localStorage) :
}
catch
{
- await localStorage.RemoveItemAsync("authToken");
+ await localStorage.RemoveItemAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
}
}
@@ -32,14 +33,14 @@ public class JwtAuthenticationStateProvider(ILocalStorageService localStorage) :
public async Task NotifyUserAuthenticationAsync(string token)
{
- await localStorage.SetItemAsStringAsync("authToken", token);
+ await localStorage.SetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY, token);
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
public async Task NotifyUserLogoutAsync()
{
- await localStorage.RemoveItemAsync("authToken");
+ await localStorage.RemoveItemAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
var nobody = new ClaimsPrincipal(new ClaimsIdentity());
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(nobody)));
diff --git a/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs b/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs
index 7989c69..3801e02 100644
--- a/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs
+++ b/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs
@@ -6,11 +6,14 @@ public class GlobalConstants
public readonly static Guid ADMINISTRATOR_USER_ID = Guid.Parse("{2AB56FCB-0CDE-4DAE-AC9C-FC7635B0D18A}");
public readonly static Guid MEMBER_ID = Guid.Parse("{BCE14DEA-1748-4A76-8485-ADEE83DF5EFD}");
- public readonly static string ADMINISTRATOR = "Administrateur";
- public readonly static string MEMBER = "Membre";
+ public const string ADMINISTRATOR = "Administrateur";
+ public const string MEMBER = "Membre";
+ public const string ADMIN_MEMBER = $"{ADMINISTRATOR}, {MEMBER}";
- public readonly static int JWT_DURATION_HOUR = 12;
+ public const int JWT_DURATION_HOUR = 12;
- public readonly static int NUMBER_PER_PAGE = 50;
+ public const int NUMBER_PER_PAGE = 50;
+
+ public const string LS_AUTH_STORAGE_KEY = "authToken";
}
\ No newline at end of file
diff --git a/src/GameIdeas/GameIdeas.Shared/Dto/GameDetailDto.cs b/src/GameIdeas/GameIdeas.Shared/Dto/GameDetailDto.cs
index 6510480..78e5548 100644
--- a/src/GameIdeas/GameIdeas.Shared/Dto/GameDetailDto.cs
+++ b/src/GameIdeas/GameIdeas.Shared/Dto/GameDetailDto.cs
@@ -6,9 +6,9 @@ public class GameDetailDto
public string? Title { get; set; }
public DateTime? ReleaseDate { get; set; }
public DateTime? CreationDate { get; set; }
- public int CreationUserId { get; set; }
+ public string CreationUserId { get; set; } = string.Empty;
public DateTime? ModificationDate { get; set; }
- public int? ModificationUserId { get; set; }
+ public string? ModificationUserId { get; set; }
public double? StorageSpace { get; set; }
public string? Description { get; set; }
public int Interest { get; set; } = 3;
diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs
index 9b0e15f..f747635 100644
--- a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs
+++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs
@@ -1,5 +1,7 @@
-using GameIdeas.Shared.Dto;
+using GameIdeas.Shared.Constants;
+using GameIdeas.Shared.Dto;
using GameIdeas.WebAPI.Services.Games;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace GameIdeas.WebAPI.Controllers;
@@ -42,6 +44,7 @@ public class GameController(
}
}
+ [Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
[HttpPost("Create")]
public async Task> CreateGame([FromBody] GameDetailDto game)
{
@@ -57,6 +60,7 @@ public class GameController(
}
}
+ [Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
[HttpPut("Update")]
public async Task> UpdateGame([FromBody] GameDetailDto game)
{
@@ -72,6 +76,7 @@ public class GameController(
}
}
+ [Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
[HttpDelete("Delete/{id:int}")]
public async Task> DeleteGame(int id)
{
diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserService.cs
index 03dc42d..65058a3 100644
--- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserService.cs
+++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserService.cs
@@ -28,6 +28,7 @@ public class UserService(UserManager userManager) : IUserService
List authClaims =
[
new Claim(ClaimTypes.Name, user.UserName ?? string.Empty),
+ new Claim(ClaimTypes.Sid, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
];