我正在使用Identity开发Blazor服务器应用程序,我对安全性有些怀疑。
在用户打开多个浏览器选项卡,然后在其中一个选项卡中注销的情况下,所有其他选项卡仍然视为用户授权。该应用程序可以一直使用到下一页刷新。
正如我从AuthenticationStateProvider
的文档中了解到的那样,它只在当前电路中工作,在另一个选项卡中看不到用户注销
是否有方法通知其他选项卡用户已注销?
经过一番挖掘,发现基本模板有一个几乎完整的解决方案。
在Identity
文件夹中有一个名为RevalidatingIdentityAuthenticationStateProvider
的类。它以检查身份SecurityStamp
是否被修改并更新AuthenticationState
的方式扩展RevalidatingServerAuthenticationStateProvider
。
该模板的问题是SecurityStamp
永远不会被修改——它是在用户登录时创建的,不会更改。
1.注销时更新安全戳
要更新身份验证状态,应该在用户在任何选项卡中注销时更新安全戳。这在Logout.cshtml
中完成。
@page
@using Microsoft.AspNetCore.Identity
@attribute [IgnoreAntiforgeryToken]
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@functions{
public async Task<IActionResult> OnGet()
{
if(SignInManager.IsSignedIn(User))
{
await SignInManager.SignOutAsync();
//add this to update security stamp
var identity = await UserManager.FindByEmailAsync(User.Identity.Name);
await UserManager.UpdateSecurityStampAsync(identity);
}
return Redirect("~/");
}
}
2.再验证间隔
类RevalidatingIdentityAuthenticationStateProvider
包含属性
protected override TimeSpan RevalidationInterval => TimeSpan.FromSeconds(30);
此属性定义两次身份验证状态检查之间的间隔。
此属性的问题在于,默认情况下,它设置为30分钟。在我看来,为了有用,间隔应该短得多。
3.在其他选项卡上注销
封装在
AuthorizeView
组件中的组件将在重新验证触发后自动切换到NotAuthorized
如果应用程序包含需要有关授权状态信息的代码,则可以这样检查:
[CascadingParameter] public Task<AuthenticationState> AuthenticationStateTask { get; set; } protected override async Task OnInitializedAsync() { var authState = await AuthenticationStateTask; var user = authState.User; if (user.Identity.IsAuthenticated) { // do something for authenticated users } else{ // do something when the user is not authenticated } }
潜在问题
- 上述解决方案使用基于计时器的身份验证状态轮询。根据用户数量和间隔长度的不同,这可能会导致性能问题
- 通过电路通知认证状态提供者的解决方案将是";"更好">
当前结果
- 测试再验证间隔设置为30秒
- 当单个用户在多个选项卡中打开一个应用程序,然后从其中一个选项卡中的应用程序注销时,该用户将在最长30秒内自动从所有其他选项卡中的该应用程序注销
这看起来不错,但它仍然缺乏对大量用户的性能测试。