Structured Security in Blazor: Exploring Logic-Driven Authorization
Tags: blazor, aspnet, cybersecurity, identity
Published: 2023-11-01 06:58:43

In Blazor applications, ensuring that users see only what they're authorized to is crucial. This guide will walk you through different methods of implementing authorization, both from within your markup and through procedural logic. 

- **1st Approach:** Using `AuthorizeView` tag.

    In this approach, we display specific parts of the markup conditionally based on the user's authorization status. It supports both role-based and policy-based authorization and can be as simple or as complex as you want.


```html

<AuthorizeView Policy="NarrowedAuthenticatedUserPolicy">
            <Authorized>
                What narrowed authenticated user sees
            </Authorized>
            <NotAuthorized>
                What unauthenticated user sees
            </NotAuthorized>
        </AuthorizeView>
        <AuthorizeView Policy="SpecialAuthenticatedUserPolicy">
            <Authorized>
                What the special authenticated user sees
            </Authorized>
</AuthorizeView>
```      



- **2nd Approach:** Using cascading `AuthenticationState` and `IAuthorizationService`.

    When you want to check for authorization as part of procedural logic in response to user interactions. In this approach, we would use the `AuthenticationState` provided by the higher level `AuthorizeRouteView` as a cascading parameter. Then, we would inject the IAuthorizationService to authorize against a role or authorization policy.

```csharp
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }

[Inject]
private IAuthorizationService AuthorizationService {get; set;}

public async Task Submit()
{
    var authState = await authenticationState;
    var authorizationResult = await AuthorizationService.AuthorizeAsync(authState.User, "NarrowedAuthenticatedUserPolicy");
    if (authorizationResult.Succeeded)
    {
        // regular user logic.
    }
    else
    {
        authorizationResult = await AuthorizationService.AuthorizeAsync(authState.User, "SpecialAuthenticatedUserPolicy");
        if (authorizationResult.Succeeded)
        {
                // Special user logic
        }
        else
        {
                // Regular authenticated user logic.
        }
    }
}
```


- **3rd Approach:** using `AuthenticationStateProvider` with `IAuthorizationService`. 

    This approach is useful when you use a property in your razor markup and need to conditionally set that property based on the user's authorization status. In this case, we would inject `AuthenticationStateProvider` to get notified about authorization changes, and use the injected `AuthorizationService` to check if the user is authorized or not.


```csharp

[Inject]
IAuthorizationService AuthorizationService { get; set; }
[Inject]
AuthenticationStateProvider AuthenticationStateProvider { get; set; }

public string UserContent = "What unauthenticated user sees";

protected override async Task OnInitializedAsync()
{
        AuthenticationStateProvider.AuthenticationStateChanged += AuthenticationStateChangedHandler;
    var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
    if (authState is not null)
    {
        await ConstructMessage(authState.User);
    }
}


private async void AuthenticationStateChangedHandler(Task<AuthenticationState> authState)
{
    var state = await authState;
    if (state is not null && state.User is not null)
    {
        await ConstructMessage(state.User);
    }
}


private async Task ConstructMessage(ClaimsPrincipal user)
{
    var authRes = await AuthorizationService.AuthorizeAsync(user, "NarrowedAuthenticatedUserPolicy");
    if (authRes.Succeeded)
    {
        UserContent = "What narrowed authenticated user sees";
    }
    else
    {
        authRes = await AuthorizationService.AuthorizeAsync(user, "SpecialAuthenticatedUserPolicy");
        if (authRes.Succeeded)
        {
            UserContent = "What the special authenticated user sees";
        }
    }
}

```


**Important Note**: here since we're using events, it is fine to do async void. The exceptions are still caught
You may think that since [CascadingAuthenticationState](https://github.com/dotnet/aspnetcore/blob/f9121bc3e976ec40a959818451d126d5126ce868/src/Components/Authorization/src/CascadingAuthenticationState.razor) uses `InvokeAsync` internally, then you should use it too. Unless you're well-versed with Blazor's intricacies, it's recommended to avoid using `InvokeAsync` from `componentBase` within your event handler

**DO NOT** try to find a workaround for not using async void for the event handler. If you use `InvokeAsync` without awaiting it, any code that throws an exception won't be caught by blazor. It depends on your use case too, however, you can see the effect by trying to throw an exception inside the following [example](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/rendering?view=aspnetcore-7.0#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) from Microsoft docs.

inside the second example, try to throw an error like so:
```csharp
private void OnTimerCallback()
{
    _ = InvokeAsync(() =>
    {
        throw new Exception();
        currentCount++;
        StateHasChanged();
    });
}
```

You will see that the component simply won't work, and no exception would be caught. This means you'd be in the dark about any errors, including their origins in the stack trace.

Further reading: https://devblogs.microsoft.com/dotnet/how-async-await-really-works/


With these approaches, you'll be better equipped to implement structured security in your Blazor applications. 

Thanks for reading, Happy Halloween :)