Problem Statement
When implementing a custom permission checking system in a Blazor Server project, I encountered difficulties creating a universal solution that requires minimal code and allows protecting resource components.
Desired Flow
- While permissions are being checked → show a loader.
- After the check:
- If access is granted → render the protected body content.
- If access is denied → render a fragment with a message about missing rights.
This is similar to the built-in [Authorize] attribute for components and the AuthorizeView wrapper for static UI elements.
I was able to implement an AuthorizeView-like wrapper, but creating an Authorize-like attribute proved problematic.
Issues Encountered
- Authorize Attribute Limitations
- Cannot render a custom fragment when access is denied (e.g., message with missing rights).
- Cannot easily pass parameters such as a list of required permissions and a custom context model
public class SecurityContext
{
public int? ProjectId { get; set; }
public int? DepartmentId { get; set; }
}
The problem is that SecurityContext in dynamicly set from url, but attribute can contains only static info. So it is not an option.
2. Layout Approach
- Attempted to use multiple layouts to handle authorization states, but Blazor only supports a single layout per page.
- Inheritance Approach
- Implemented a base component (
SecurityComponentBaseCore + SecurityComponentBase) that handles loading, access checks, and error messages.
Example: SecurityComponentBaseCore.razor
@if (Loading)
{
<FluentStack HorizontalAlignment="HorizontalAlignment.Center" VerticalAlignment="VerticalAlignment.Center" Style="height: 100%">
<FluentProgressRing style="width: 62px; height: 62px;" />
</FluentStack>
}
else if (HasAccess)
{
@Body
}
else
{
<FluentMessageBar Intent="MessageIntent.Warning">@ErrorMessage</FluentMessageBar>
}
@code {
public virtual bool Loading { get; set; } = true;
public virtual bool HasAccess { get; set; } = false;
public virtual string ErrorMessage { get; set; } = string.Empty;
private protected virtual RenderFragment Body => builder => { };
}
Example: SecurityComponentBase.cs
public abstract class SecurityComponentBase : SecurityComponentBaseCore
{
[Inject] protected ISecurityManager SecurityManager { get; set; } = default!;
[Inject] protected ILogger<SecurityComponentBase> Logger { get; set; } = default!;
protected virtual SecurityContext Context { get; } = new SecurityContext();
protected virtual List<string> RequiredPermissions { get; } = [];
private protected sealed override RenderFragment Body => BuildRenderTree;
protected new virtual void BuildRenderTree(RenderTreeBuilder builder) { }
protected override async Task OnInitializedAsync()
{
try
{
Loading = true;
var res = await SecurityManager.HasAccess(Context, RequiredPermissions);
HasAccess = res.IsSuccess;
Loading = false;
if (!HasAccess)
{
ErrorMessage = res.ErrorMessage ?? "Access denied";
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Error checking permissions");
HasAccess = false;
ErrorMessage = "Error checking permissions";
}
finally
{
Loading = false;
}
}
}
Example: MyComponent.razor
@inherits SecurityComponentBase
<div>
content
</div>
@code {
protected override List<string> RequiredPermissions { get; } = ["right1", "right2"];
protected override SecurityContext Context { get; } = new SecurityContext { ProjectId = 1 };
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
// Secure work here
await Task.Delay(5000);
}
}
The problem in this scenario is that calling StateHasChanged() anywhere results in:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
This prevents showing the loader only during permission checks (instead it persists until the entire OnInitializedAsync of the derived component finishes and a 5‑second delay allows this to be shown). The call to StateHasChanged() is necessary in this scenario because it should trigger a re‑render: once the permission check completes, the component should update its UI so that the loader is replaced by either the protected content or the denied fragment. Without this re‑render, the loader remains visible longer than intended.
Question
Is there a proper Blazor solution that allows building an Authorize-like mechanism with:
- A loader displayed during the permission check
- A custom denied fragment that shows missing rights
- The ability to pass both a list of required permissions and a context model (
SecurityContext)
Is there a recommended pattern or framework support for this scenario?
Alternatively, could the existing Authorize attribute be extended or modified to handle these requirements?
Attempting to implement something that was not originally intended feels fragile, especially since Blazor evolves quickly and such a workaround may stop functioning in future versions (I have already experienced this).
Therefore, the core question is: Is there a proper, supported way to create an equivalent of Authorize or a reworked version that will reliably function in Blazor?
It is possible that I have not fully understood all aspects of Blazor’s authorization system and may be missing something important. I would be glad to read any comments, clarifications, or suggestions.
Problem Statement
When implementing a custom permission checking system in a Blazor Server project, I encountered difficulties creating a universal solution that requires minimal code and allows protecting resource components.
Desired Flow
This is similar to the built-in
[Authorize]attribute for components and theAuthorizeViewwrapper for static UI elements.I was able to implement an
AuthorizeView-like wrapper, but creating anAuthorize-like attribute proved problematic.Issues Encountered
The problem is that SecurityContext in dynamicly set from url, but attribute can contains only static info. So it is not an option.
2. Layout Approach
SecurityComponentBaseCore+SecurityComponentBase) that handles loading, access checks, and error messages.Example:
SecurityComponentBaseCore.razorExample:
SecurityComponentBase.csExample:
MyComponent.razorThe problem in this scenario is that calling
StateHasChanged()anywhere results in:This prevents showing the loader only during permission checks (instead it persists until the entire
OnInitializedAsyncof the derived component finishes and a 5‑second delay allows this to be shown). The call toStateHasChanged()is necessary in this scenario because it should trigger a re‑render: once the permission check completes, the component should update its UI so that the loader is replaced by either the protected content or the denied fragment. Without this re‑render, the loader remains visible longer than intended.Question
Is there a proper Blazor solution that allows building an
Authorize-like mechanism with:SecurityContext)Is there a recommended pattern or framework support for this scenario?
Alternatively, could the existing
Authorizeattribute be extended or modified to handle these requirements?Attempting to implement something that was not originally intended feels fragile, especially since Blazor evolves quickly and such a workaround may stop functioning in future versions (I have already experienced this).
Therefore, the core question is: Is there a proper, supported way to create an equivalent of
Authorizeor a reworked version that will reliably function in Blazor?It is possible that I have not fully understood all aspects of Blazor’s authorization system and may be missing something important. I would be glad to read any comments, clarifications, or suggestions.