如何使用 Blazor Server 对用户进行身份验证
Posted
技术标签:
【中文标题】如何使用 Blazor Server 对用户进行身份验证【英文标题】:How to authenticate a user with Blazor Server 【发布时间】:2020-06-08 12:52:53 【问题描述】:我有一个使用 MongoDB 作为数据库的 Blazor Server 应用程序,因此我正在尝试使用它来实现身份验证。所以我可以在剃须刀页面中使用<Authenticted>, <AuthorizeView Roles="admin">
和其他类似的标签。
内置的身份验证模板使用 SQL Server,在这种情况下我不想要它,并且没有一个明确的示例说明如何自己使用另一个数据库进行操作。鉴于微软提供的示例here
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
namespace BlazorSample.Services
public class CustomAuthStateProvider : AuthenticationStateProvider
public override Task<AuthenticationState> GetAuthenticationStateAsync()
var identity = new ClaimsIdentity(new[]
new Claim(ClaimTypes.Name, "mrfibuli"),
, "Fake authentication type");
var user = new ClaimsPrincipal(identity);
return Task.FromResult(new AuthenticationState(user));
应该如何在应用程序中使用它?您显然不会硬编码单个值和值类型,作为您唯一的身份验证来源。那么应该如何参数化呢?具有本地属性,例如:
Username get; set;
UserType get; set;
在这种情况下,你会在哪里设置?
然后你将如何使用它来验证用户?我在ConfigurationServices(...)
方法下的启动文件中添加了类:
...
services.AddScoped<AuthenticationStateProvider, MongoAuthenticationStateProvider>();
...
我不知道如何验证任何人。我想您可以通过多种方式验证用户名和密码,然后当您知道这很好时,您可以继续更新 .NET 中的身份验证。我正在关注一个教程,他们在后面的代码中提出了类似的建议:
using System;
using System.Linq;
using DocsPlatform.Services;
using System.Threading.Tasks;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
namespace DocsPlatform.Pages
public class LoginBase : ComponentBase
[CascadingParameter]
private Task<AuthenticationState> authStateTask get; set;
protected string username get; set;
protected string password get; set;
protected async Task LoginUser()
bool isValid = true;
isValid = dbService.ValidateUser(username, password);
string email = dbService.GetEmail(username);
var claims = new List<Claim>
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Email, email),
;
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity));
return NavigationManager.NavigateTo("/");
但是,返回中的导航不起作用(他们甚至没有解释他们的代码是如何编译的),并且 SignInAsync() 方法在他们展示的方式中不可用。同样,我不知道他们的代码是如何编译的。那么通常如何做到这一点呢?
除了数百个仅使用内置 SQL Server 模板的示例之外,我找不到任何教程、示例等。在哪里可以找到有关如何使用它的详细信息?除了“使用内置模板”或文档链接here 之外的任何内容都将不胜感激,因为它们都没有解释如何执行此操作。
【问题讨论】:
完美的问题说明了这是多么糟糕的记录。我和你在同一个地方。 【参考方案1】:内置的身份验证模板使用 SQL Server,在这种情况下我不想要它,并且没有明确的示例说明如何自己使用另一个数据库进行操作
我猜你使用的是 ASP.NET Core Identity,对吧?如果您正在寻找使用其他提供商的方式,请参阅official docs
应该如何在应用程序中使用它?您显然不会将单个值和值类型硬编码为唯一的身份验证来源。那么应该如何参数化呢?
由于您使用的是 Blazor Server(而不是 Blazor Wasm),因此您不必自定义 GetAuthenticationStateAsync()
方法,然后手动创建主体。已经有一个内置的ServerAuthenticationStateProvider
,它既继承自AuthenticationStateProvider
,又实现了IHostEnvironmentAuthenticationStateProvider
接口:
// source code of the built-in ServerAuthenticationStateProvider
public class ServerAuthenticationStateProvider : AuthenticationStateProvider, IHostEnvironmentAuthenticationStateProvider
private Task<AuthenticationState> _authenticationStateTask;
/// <inheritdoc />
public override Task<AuthenticationState> GetAuthenticationStateAsync()
=> _authenticationStateTask
?? throw new InvalidOperationException($"nameof(GetAuthenticationStateAsync) was called before nameof(SetAuthenticationState).");
/// <inheritdoc />
public void SetAuthenticationState(Task<AuthenticationState> authenticationStateTask)
_authenticationStateTask = authenticationStateTask ?? throw new ArgumentNullException(nameof(authenticationStateTask));
NotifyAuthenticationStateChanged(_authenticationStateTask);
正如您在上面看到的,GetAuthenticationStateAsync()
将返回由IHostEnvironmentAuthenticationStateProvider
设置的身份验证状态。所以你需要注入一个IHostEnvironmentAuthenticationStateProvider
并调用IHostEnvironmentAuthenticationStateProvider::SetAuthenticationState(...)
。最后身份验证状态会自动发送到 Blazor <Authorize/>
。
其实上面的ServerAuthenticationStateProvider
不知道principal是否还有效。所以还有另一个内置的具体类:RevalidatingServerAuthenticationStateProvider
。
以上代码适用于每种身份验证方案,包括 ASP.NET Core Identity、JwtBearer、AAD 等。您使用什么身份验证方案或使用哪个数据库都没有关系。只需扩展 RevalidatingServerAuthenticationStateProvider
类即可。
例如,如果您使用的是 ASP.NET Core Identity(您可能会看到与 Cookies 相关的问题(请参阅 this thread),它将生成一个 RevalidatingIdentityAuthenticationStateProvider
类使用UserManager<TUser>
来验证principal是否有效。
public class RevalidatingIdentityAuthenticationStateProvider<TUser>
: RevalidatingServerAuthenticationStateProvider where TUser : class
...
protected override async Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState, CancellationToken cancellationToken)
// Get the user manager from a new scope to ensure it fetches fresh data
// use the UserManager to determine whether the current principal is still valid
由于 ASP.NET Core 标识 不仅限于 SQL Server,RevalidatingIdentityAuthenticationStateProvider
也适用于其他数据库。如果您想使用 MongoDB,请随意创建自定义 MyMongoDbRevalidatingAuthenticationStateProvider
。
然后你将如何使用它来验证用户
只需像这样声明组件:
<AuthorizeView>
<Authorized>
...
</Authorized>
<NotAuthorized>
...
</NotAuthorized>
</AuthorizeView>
如果您使用默认的RevalidatingServerAuthenticationStateProvider
,您将不手动执行此操作。在 Blazor Server Side 中,身份验证由 AuthenticationMiddleware
完成,然后身份验证状态将自动传递给 <AuthorizeView/>
。并且当认证状态过期时,<AuthorizeView/>
也会自动更新。
返回中的导航不起作用
实际上,您的代码在导航之前应该会失败:
HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity));
请注意,SignIn() 方法将尝试通过 HTTP 发送 cookie。但是,大多数情况下,连接建立后没有 HTTP。其实我有answered an exactly same question several month ago。
简而言之:
-
无论您使用哪种身份验证方案,都可以根据需要实现
RevalidatingServerAuthenticationStateProvider
,如RevalidatingIdentityAuthenticationStateProvider
。
如果您使用的是 ASP.NET Core Identity,则会为您生成一个 RevalidatingIdentityAuthenticationStateProvider
。
如果您想使用 ASP.NET Core Identity + MongoDB,请关注official docs 实现这样的功能。
如果要使用 ASP.NET Core Identity + Blazor Server Side,并使用 SignIn(...) 发送 cookie,请不要直接这样做。有关详细信息,请参阅this thread。
【讨论】:
你有关于如何实现你提到的类的项目或示例代码吗?以上是关于如何使用 Blazor Server 对用户进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用服务器端 Blazor,在连接到 SQL Server 数据库时如何使用 Windows 身份验证模拟用户?
如何通过组织身份验证从 Blazor Server 中的身份获取用户属性
Blazor WebAssembly Server 项目如何引用客户端索引?