Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@page "/authorized-test"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

<MudPage Class="d-flex align-center justify-center" FullScreen="FullScreen.FullWithoutAppbar" Column="1" Row="1">
<MudPaper Class="pa-8" Style="max-width: 520px; width: 100%;" Elevation="0" Outlined="true">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@page "/home"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

@inject IUAuthClient UAuthClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@page "/authorized-test"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

<MudPage Class="d-flex align-center justify-center" FullScreen="FullScreen.FullWithoutAppbar" Column="1" Row="1">
<MudPaper Class="pa-8" Style="max-width: 520px; width: 100%;" Elevation="0" Outlined="true">
Expand All @@ -13,7 +14,7 @@
</MudText>

<MudStack Row="true" Spacing="2" Class="mt-2">
<MudButton Href="/home" Color="Color.Primary" Variant="Variant.Filled">Go Profile</MudButton>
<MudButton Href="/home" Color="Color.Primary" Variant="Variant.Filled">Go Home Page</MudButton>
</MudStack>

<MudDivider Class="my-2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@page "/home"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

@inject IUAuthClient UAuthClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@page "/authorized-test"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

<MudPage Class="d-flex align-center justify-center" FullScreen="FullScreen.FullWithoutAppbar" Column="1" Row="1">
<MudPaper Class="pa-8" Style="max-width: 520px; width: 100%;" Elevation="0" Outlined="true">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@page "/home"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

@inject IUAuthClient UAuthClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@page "/authorized-test"
@attribute [Authorize]
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

<MudPage Class="d-flex align-center justify-center" FullScreen="FullScreen.FullWithoutAppbar" Column="1" Row="1">
<MudPaper Class="pa-8" Style="max-width: 520px; width: 100%;" Elevation="0" Outlined="true">
Expand All @@ -13,7 +14,7 @@
</MudText>

<MudStack Row="true" Spacing="2" Class="mt-2">
<MudButton Href="/home" Color="Color.Primary" Variant="Variant.Filled">Go Profile</MudButton>
<MudButton Href="/home" Color="Color.Primary" Variant="Variant.Filled">Go Home Page</MudButton>
</MudStack>

<MudDivider Class="my-2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@page "/home"
@* To make Authorize attribute to work, add ResourceApi in Program.cs, but it affects performance significantly *@
@* @attribute [Authorize] *@
@attribute [UAuthAuthorize]
@inherits UAuthFlowPageBase

@inject IUAuthClient UAuthClient
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace CodeBeam.UltimateAuth.Client.Blazor;

[AttributeUsage(AttributeTargets.Class)]
public sealed class UAuthAuthorizeAttribute : Attribute
{
public string? Roles { get; set; }
public string? Permissions { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CodeBeam.UltimateAuth.Core.Contracts;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.WebUtilities;
using System.Text;
using System.Text.Json;
Expand All @@ -8,8 +7,6 @@ namespace CodeBeam.UltimateAuth.Client.Blazor;

public abstract class UAuthFlowPageBase : UAuthReactiveComponentBase
{
[Inject] protected NavigationManager Nav { get; set; } = default!;

protected AuthFlowPayload? UAuthPayload { get; private set; }
protected string? ReturnUrl { get; private set; }
protected bool ShouldFocus { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ namespace CodeBeam.UltimateAuth.Client.Blazor;
public abstract class UAuthReactiveComponentBase : ComponentBase, IDisposable
{
private UAuthState? _previousState;
private bool _rendered;

[CascadingParameter]
protected UAuthState AuthState { get; set; } = default!;

[Inject] protected NavigationManager Nav { get; set; } = default!;

/// <summary>
/// Automatically re-render when UAuthState changes.
/// Can be overridden to disable.
Expand All @@ -31,12 +34,24 @@ protected override void OnParametersSet()
AuthState.Changed += OnAuthStateChanged;
_previousState = AuthState;
}

EvaluateAuthorization();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);

if (firstRender)
_rendered = true;
}

private void OnAuthStateChanged(UAuthStateChangeReason reason)
{
HandleAuthStateChanged(reason);

EvaluateAuthorization();

if (AutoRefreshOnAuthStateChanged)
_ = InvokeAsync(StateHasChanged);
}
Expand All @@ -48,6 +63,54 @@ protected virtual void HandleAuthStateChanged(UAuthStateChangeReason reason)
{
}

private void EvaluateAuthorization()
{
var attr = GetType()
.GetCustomAttributes(typeof(UAuthAuthorizeAttribute), true)
.FirstOrDefault() as UAuthAuthorizeAttribute;

if (attr is null)
return;

if (_rendered && !AuthState.IsAuthenticated)
{
OnUnauthorized();
return;
}

if (_rendered && !string.IsNullOrEmpty(attr.Roles))
{
var roles = attr.Roles.Split(',');

if (!roles.Any(r => AuthState.IsInRole(r.Trim())))
{
OnForbidden();
return;
}
}

if (_rendered && !string.IsNullOrEmpty(attr.Permissions))
{
var permissions = attr.Permissions.Split(',');

if (!permissions.Any(p => AuthState.HasPermission(p.Trim())))
{
OnForbidden();
return;
}
}
}

protected virtual void OnUnauthorized()
{
Nav.NavigateTo("/");
}

protected virtual void OnForbidden()
{
Nav.NavigateTo("/forbidden");
}

public virtual void Dispose()
{
if (_previousState is not null)
Expand Down
Loading