我想完全绕过 AspnetCore 身份,而是使用对当前用户进行身份验证的自定义方法。
但是,我仍然希望现有的授权框架能够发挥作用。换句话说,我希望能够使用
AuthorizeView
和 @attribute [Authorize]
来维护安全。
我搜索了又搜索,但没有找到任何有关如何实现此操作的详细信息。
好的,您想在 Blazor Server 应用程序中实现自定义身份验证。换句话说,您希望使用与 ASP.net Identity 不同的方法来注册和验证用户。但您仍然希望在页面上使用内置的
Authorization
功能,例如 AuthorizedView 和 [Authorize]
属性。
请注意,我在这里所说的仅适用于 Blazor 服务器应用程序。如果您使用 Blazor Web assembly,则需要不同的解决方案,此处未介绍,因为它是完全不同的安全模型。
好的,开始吧:要实现自定义身份验证,您需要实现一个名为
AuthenticationStateProvider
的类。
这里是用于创建自定义 AuthenticationStateProvider 的 docs 的链接。但是,文档没有给出完整的解决方案,因此这里是基于文档的其余部分:
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
public CustomAuthenticationStateProvider()
{
this.CurrentUser = this.GetAnonymous();
}
private ClaimsPrincipal CurrentUser { get; set; }
private ClaimsPrincipal GetUser(string userName, string id, string role)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes. Sid, id),
new Claim(ClaimTypes.Name, userName),
new Claim(ClaimTypes.Role, role)
}, "Authentication type");
return new ClaimsPrincipal(identity);
}
private ClaimsPrincipal GetAnonymous()
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Sid, "0"),
new Claim(ClaimTypes.Name, "Anonymous"),
new Claim(ClaimTypes.Role, "Anonymous")
}, null);
return new ClaimsPrincipal(identity);
}
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var task = Task.FromResult(new AuthenticationState(this.CurrentUser));
return task;
}
public Task<AuthenticationState> ChangeUser(string username, string id, string role)
{
this.CurrentUser = this.GetUser(username, id, role);
var task = this.GetAuthenticationStateAsync();
this.NotifyAuthenticationStateChanged(task);
return task;
}
public Task<AuthenticationState> Logout()
{
this.CurrentUser = this.GetAnonymous();
var task = this.GetAuthenticationStateAsync();
this.NotifyAuthenticationStateChanged(task);
return task;
}
}
完成后,在program.cs中注册它,并注释掉现有的:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
//builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
现在您可以使用它来登录您的用户:
<AuthorizeView>
<Authorized>
<div class="m-1 p-1 text-white">
Welcome, @user.Identity.Name
</div>
</Authorized>
<NotAuthorized>
<div>
<div>
Your email<input type="text" @bind-value="@Email" />
</div>
<div>
Your password<input type="text" @bind-value="@Password" />
</div>
<div>
<button style="width:70px;" @onclick="Login">Submit</button>
</div>
</div>
</NotAuthorized>
</AuthorizeView>
@code{
public string Email { get; set; }
public string Password { get; set; }
public string Id { get; set; } = "12345";
[CascadingParameter] public Task<AuthenticationState> AuthTask { get; set; }
[Inject] private AuthenticationStateProvider AuthState { get; set; }
private System.Security.Claims.ClaimsPrincipal user;
protected async override Task OnInitializedAsync()
{
var authState = await AuthTask;
this.user = authState.User;
}
public async Task Login()
{
//Todo: Validate against actual database.
var authState = await ((CustomAuthenticationStateProvider)AuthState).ChangeUser(this.Email, this.Id, "Associate");
this.user = authState.User;
}
}
在您的实现中,当然您需要根据您认为合适的方式授权您的用户。
免责声明:我无论如何都不是安全专家。除了我吃午饭时进行的简短烟雾测试之外,上述内容尚未经过测试。
请注意,这不会让用户关闭页面或刷新页面。
但是,完成上述操作后,内置的授权框架(包括角色)就可以工作了。
确实,文档中的所有信息都相当分散。 这就是我创建这个示例的原因。
https://github.com/iso8859/AspNetCoreAuthMultiLang
在文件 myServerAuthenticationStateProvider.cs 的末尾,您可以扮演角色。
result = new AuthenticationState(
new ClaimsPrincipal(
new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, m_login),
new Claim(ClaimTypes.Role, "demo_role"),
new Claim(ClaimTypes.Role, "Admin"),
}, "PutAppNameHere"
)));
这篇文章似乎很旧,但我也开始将 Azure B2C 与 Blazor 服务器 .net 8 集成,并想知道是否有一种方法可以为经过身份验证的用户传递访问令牌,而无需将其保存在应用程序中的某个位置。 就像下面的代码一样,我有 blazor wasm .net6 公共类 CustomAuthorizationMessageHandler : AuthorizationMessageHandler { 公共 CustomAuthorizationMessageHandler(IAccessTokenProvider 提供商, 导航管理器 (navigationManager) :基础(提供者,导航管理器) { 配置处理程序( authorizedUrls: new[] { BaseUri }); } }
但是 AuthorizationMessageHandler 类用于 Web 程序集,是否有类似的设置可以与 blazor 服务器一起使用。我需要访问令牌才能附加到我的安全休息 API。