Moin Moin. Ich bin mir nicht ganz sicher, ob meine Angehensweise hier die Richtige ist...
Ich habe eine Blazor Server .NET 8 App und verwende Identity. Ich habe einen ClientService registriert und habe in meiner GetClient Methode eine Owner-Prüfung, die mit der ID des Users durchgeführt werden soll.
public async Task<ServiceResponse<Client>> GetClient(int clientId, string ownerId)
{
try
{
var client = await _mainDbContext.Clients.FirstOrDefaultAsync(x => x.Id == clientId);
if (client == null)
{
return await Task.FromResult(new ServiceResponse<Client> { Success = false, Message = "Client not found" });
}
if (client.OwnerId != ownerId)
{
return await Task.FromResult(new ServiceResponse<Client> { Success = false, Message = "You are not the owner of this client" });
}
return await Task.FromResult(new ServiceResponse<Client> { Success = true, Data = client });
}
catch
{
return await ErrorHandler.ThrowErrorAsync<Client>();
}
}
Im Frontend greife ich auf diesen Service zu. Ich habe das [Authorize]-Attribut gesetzt und hole mir den User über den UserAccessor von Identity.
Meine Frage ist, ob ich jetzt einfach die ID vom User in diesen ClientService übergeben kann, oder ob das theoretisch manipuliert werden könnte?
Mein Code:
Client.razor.cs
namespace Test.Components.Pages
{
public class ClientBase : ComponentBase
{
[Parameter] public int ClientId { get; set; }
[Inject] IClientService ClientService { get; set; }
[Inject] AuthenticationStateProvider _authenticationStateProvider { get; set; }
[Inject] IdentityUserAccessor UserAccessor { get; set; }
[Inject] IHttpContextAccessor _httpContextAccessor { get; set; }
[Inject] NavigationManager NavigationManager { get; set; }
protected string message;
protected bool IsConnected = false;
protected bool IsConnecting = false;
protected string ErrorMsg = string.Empty;
protected Shared.Models.Client client;
protected override async Task OnInitializedAsync()
{
ApplicationUser user = null;
if (_httpContextAccessor.HttpContext != null)
user = await UserAccessor.GetRequiredUserAsync(_httpContextAccessor.HttpContext);
if(user == null)
{
NavigationManager.NavigateTo("/login", true);
return;
}
if(ClientId <= 0)
{
var result = await ClientService.GetClient(ClientId, user.Id);
if (result.Success && result.Data != null)
{
client = result.Data;
var webSocket = await WebSocketManagerService.GetWebSocketAsyncOrNull(client.CustomId);
if (webSocket != null)
{
IsConnected = true;
}
}
}
}
}
}
Client.razor
@page "/client/{ClientId:int}"
@inherits ClientBase
@rendermode InteractiveServer
@attribute [Authorize]
<PageTitle>Client</PageTitle>
@if (client != null)
{
<h1 style="text-align: center;">@client.Id</h1>
<hr />
}
@if(IsConnected)
{
<button class="btn btn-danger" @onclick="Disconnect">Disconnect from client</button>
<p>Connected</p>
}
@if (IsConnected == false)
{
@if (IsConnecting)
{
<p>Connecting...</p>
}
@if(IsConnecting == false)
{
<button class="btn btn-success" @onclick="Connect">Connect to client</button>
<p>Not connected</p>
}
}
@if(!string.IsNullOrEmpty(ErrorMsg))
{
<p>@ErrorMsg</p>
}
Hallo,
zunächst die Bitte in Zukunft den richtigen Forenbereich zu wählen - dann ist die Wahrscheinlichkeit auch höher, dass Dir jemand antwortet.
Ein Code-Snippet ist das hier nicht.
Danach empfehl ich Dir den Blog von Damien Bowden: https://damienbod.com/
Er hat viel Tutorials zu ASP.NET Core und Blazor und verschiedene Auth-Szenarien.
Zu Deinem Vorgehen allgemein: verwende kein Strings als Fehlerwerte, sondern Results oder Enums.
Das fällt unter: https://learn.microsoft.com/en-us/dotnet/standard/exceptions/best-practices-for-exceptions
Im Frontend kannst Du das dann auf Texte mappen; aber nicht in Deiner Logik.
Meine Frage ist, ob ich jetzt einfach die ID vom User in diesen ClientService übergeben kann, oder ob das theoretisch manipuliert werden könnte?
Deine Id stammt - wenn ich Dein Setup richtig verstehe - aus dem Token.
Wenn Dein Setup also einen Token richtig validiert, dann kannst Du diesen Werten prinzipiell vertrauen.
PS: in den meisten Komponenten von ASP.NET bzw. Blazor kannst Du direkt auf den HttpContext zugreifen (zB this.Request.Context) und einer Methode übergeben; das sollte man dem IHttpContextAccessor vorziehen.
Siehe:
Zitat von David Fowler: https://twitter.com/davidfowl/status/1563935285754593281
Yea, the IHttpContextAccessor was a mistake. I can say that now after 7 years https://github.com/dotnet/aspnetcore/issues/42040#issuecomment-1225031868…. AsyncLocal<T> should be used sparingly... #dotnet #aspnetcore
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code