Search code examples
c#asp.net-coreasp.net-identityblazorblazor-server-side

Blazor Allow Anonymous For Razor Page


I have a .net cor 3.1 Blazor server project. I use the default identity system in this project. I want to access a specific razor page without login. How do I do that? Any Idea?

I tried adding @attribute [AllowAnonymous] to the razor page. But it did not work for me

_Host.cshtml

page "/"
@using Microsoft.AspNetCore.Authorization
@namespace has.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@attribute [Authorize]
@{
    Layout = null;
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>has</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="css/custom_styles.css" rel="stylesheet" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link href="_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet" />
    <link href="_content/Blazor.ContextMenu/blazorContextMenu.min.css" rel="stylesheet" />
    <script src="_content/BlazorInputFile/inputfile.js"></script>
    <script src="~/js/site.js"></script>
</head>
<body>
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.server.js"></script>
    <script src="_content/AntDesign/js/ant-design-blazor.js"></script>
    <script src="_content/Blazor.ContextMenu/blazorContextMenu.min.js"></script>
    <script src="https://kit.fontawesome.com/863157cf0e.js" crossorigin="anonymous"></script>
</body>
</html>

App.razor

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <Error404 />
            </LayoutView>
        </NotFound>
    </Router>

    <AntContainer />
</CascadingAuthenticationState>

Solution

  • I found an answer. I created another _Host.cshtml with @attribute [AllowAnonymous] in a separate folder inside of the Pages folder and I put my razor page in that folder.

    Add @layout PublicLayout to your anonymous access component. In my case, MyAnonymousComponent.razor. PublicLayout is PublicSection/PublicLayout.razor

    My project structure is like this

    MyProject
       -Pages
          -Section1
          -Section2
          -Shared
              _Layout.cshtml
          -PublicSection     // This folder has anonymous access components
              _Host.cshtml
              _Layout.cshtml
              MyAnonymousComponent.razor
              PublicApp.razor
              PublicLayout.razor
           _Host.cshtml
    
       -Shared      
          MainLayout.razor
    
       App.razor
       _Imports.razor
       Program.cs
       Startup.cs      
      
    

    PublicSection/_Host.cshtml

    @page "/publicsection"
    @using has.Pages.PublicRazor
    @using Microsoft.AspNetCore.Authorization
    @namespace has.Pages
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @attribute [AllowAnonymous]
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    <html lang="en">
    <head>    
        <base href="~/PublicSection" />
        // rest is same as Original _Host.cshtml file
    </head>
    <body>
        <app>
            <component type="typeof(PublicApp)" render-mode="ServerPrerendered" />
        </app>
    
        // rest is same as Original _Host.cshtml file
    </body>
    </html>
    

    PublicApp.razor

    <CascadingAuthenticationState>
        <Router AppAssembly="@typeof(Program).Assembly">
            <Found Context="routeData">
                <RouteView RouteData="@routeData" DefaultLayout="@typeof(PublicLayout)" />
            </Found>
            <NotFound>
                <LayoutView Layout="@typeof(PublicLayout)">
                    <Error404 />
                </LayoutView>
            </NotFound>
        </Router>
        <AntContainer />
    </CascadingAuthenticationState>
    

    PublicLayout.razor

    @inherits LayoutComponentBase;
    
    <Content Class="site-layout-background content-pan">
        @Body
    </Content>
    
    @code {
        
    }
    

    Startup.cs

    ...
    app.UseEndpoints(endpoints =>
        {
           endpoints.MapControllers();
           endpoints.MapBlazorHub();
           endpoints.MapFallbackToPage("~/PublicSection/{**segment}","/PublicRazor/_Host");
           endpoints.MapFallbackToPage("/_Host");
        });
    ...