根据Microsoft的建议,我使用自定义AuthenticationStateProvider服务来处理身份验证/授权。
在razor组件中,我可以使用[authorization]属性或AuthorizeView/Authorized/NotAuthorized标签。
如果我尝试通过任何razor组件页面进入页面,它会重定向到登录页面,因为用户没有经过身份验证。
现在,我已经添加了一个Controller Page,它工作得很好,但是我无法控制用户是否经过身份验证,以便为控制器页面中包含的方法提供服务。
如果我手动输入URL到控制器,而不是被重定向到登录页面,它实际上导航并执行方法。
如何将身份验证/授权控件添加到控制器页面或razor页面,就像它正确处理razor组件的身份验证/授权一样?
我已经试过了:
添加[authorization]属性到控制器页面类。当我这样做的时候,我得到了一个异常:
InvalidOperationException: Endpoint xxxx包含授权元数据,但没有找到支持授权的中间件。通过在应用程序启动代码中添加app.UseAuthorization()来配置应用程序启动。如果有对app.UseRouting()和app.UseEndpoints(…)的调用,则对app.UseAuthorization()的调用必须在它们之间进行。
所以我添加了app.UseAuthorization(), app.UserAuthorization()正如消息所说(直到此时身份验证工作才需要),然后在试图到达控制器页面时出现另一个异常:
InvalidOperationException: No authenticationScheme was specified, and there is No defaultchallengesscheme found。默认方案可以使用AddAuthentication(string defaultScheme)或AddAuthentication(Action configureOptions)来设置。
如果我使用AddAuthentication方法,我相信我将进入另一个不属于使用Blazor服务器端页面的领域。
在任何情况下,我创建的控制器页面是用于下载文件的:
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);
}
}
}
我还尝试使用剃刀页面而不是控制器页面,但我最终遇到了同样的问题,即如果用户为了进入剃刀页面而经过身份验证,我无法控制。
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);
}
}
}
提前感谢。
我想坚持使用Blazor(服务器端)最佳实践,而不是试图通过脚手架,javascript或其他方式规避它。
我最终使用的是通过cookie(在Blazor之外)进行身份验证,因此整个站点(包括控制器和Blazor)都在一个唯一的身份验证方法下(通过cookie)。同时(在Blazor"环境"中),我继续使用AuthenticationStateProvider。这意味着我通过cookie和AuthenticationStateProvider并行跟踪身份验证,所以当我登录或注销时,我必须确保影响两种身份验证方法(Blazor外部的cookie和Blazor的AuthenticationStateProvider)。