简体   繁体   中英

Blazor (server side) authentication and controller pages

As per Microsoft's recommendation, I am using a custom AuthenticationStateProvider service for handling authentication/authorization.

It all works fine within razor components, where I can use the [Authorize] attribute or the AuthorizeView/Authorized/NotAuthorized tags.

If I try to enter the page via any razor component page, it redirects to the login page because the user is not authenticated.

Now, I've added a Controller Page, which works just fine, but I can't control whether the user is authenticated or not in order to serve the method included in the controller page.

If I manually enter the URL to the controller, instead of being redirected to the login page, it actually navigates and executes the method.

How can I add authentication/authorization control to controller pages or razor pages just as it correctly handles authentication/authorization for razor components?

What I've tried so far:

Adding the [Authorize] attribute to the controller page class. When I did that I got the exception:

InvalidOperationException: Endpoint xxxx contains authorization metadata, but a middleware was not found that supports authorization. Configure your application startup by adding app.UseAuthorization() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(...), the call to app.UseAuthorization() must go between them.

So I added app.UseAuthorization(), app.UserAuthorization() as the message said (which was not needed until this point for authentication to work), which then thew another exception when trying to reach the controller page:

InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action configureOptions).

If I used the AddAuthentication method I believe I'd be entering another territory which does not belong to using a Blazor server side page anymore.

In any case the controller page I created was for dowloading a file:

public class DownloadController : Controller
{
    private readonly IWebHostEnvironment environment;
    
    public DownloadController(IWebHostEnvironment environment, AuthenticationStateProvider authenticationStateProvider)
    {
        this.environment = environment;
    }
    
    public IActionResult OnGet()
    {
    
        try
        {
            var fs = new FileStream("excel.xlsx", FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
            return File(
                fileStream: fs,
                contentType: System.Net.Mime.MediaTypeNames.Application.Octet,
                fileDownloadName: "excel.xlsx");
        }
        catch (Exception e)
        {
            return StatusCode(500, e.Message);
        }
    }
}

I also tried using a razor page instead of a controller page, but I ended up with the same problem that I can't control if the user is authenticated in order to get to the razor page.

public class DownloadModel : PageModel
{
    public IActionResult OnGet()
    {
        try
        {
            var fs = new FileStream("excel.xlsx", FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
            return File(
                fileStream: fs,
                contentType: System.Net.Mime.MediaTypeNames.Application.Octet,
                fileDownloadName: "excel.xlsx");
        }
        catch (Exception e)
        {
            return StatusCode(500, e.Message);
        }
    }
}

Thanks in advance.

I'd like to stick to just using Blazor (server-side) best practices, and not try to circumvent it via scaffoldding, javascript, or whatever.

What I ended up using is authentication via cookies (outside Blazor), so the entire site (included controllers and Blazor) is under one unique authentication method (via cookies). At the same time (inside the Blazor "environment"), I keep using AuthenticationStateProvider. That means I'm keeping track of the authentication via cookies and AuthenticationStateProvider in parallel, so when I log in or log out I have to make sure to impact both authentication methods (cookies for outside of Blazor and AuthenticationStateProvider for Blazor).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM