获取Blazor服务器中基于Cookie的身份验证和授权服务中的当前登录用户



我使用此repo在Blazor服务器上使用cookie实现身份验证和授权。

假设我想在HotelRoomService.cs中的DeleteHotelRoomAsync方法中检索当前登录的用户,以记录删除房间的用户的信息。

public async Task<int> DeleteHotelRoomAsync(int roomId)
{
var roomDetails = await _dbContext.HotelRooms.FindAsync(roomId);
if (roomDetails == null)
{
return 0;
}
_dbContext.HotelRooms.Remove(roomDetails);
//ToDo
//_dbContext.DbLog.Add(userId,roomId);
return await _dbContext.SaveChangesAsync();
}

我不能使用AuthenticationStateProvider,因为它在那里或那里,因为基于cookie的系统,所以AuthenticationStateProvider在下面的代码中为null。

我使用了HttpContextAccessor,可以如下检索经过身份验证的userId,但由于Microsoft的建议,我无法使用HttpContextAccessor。

public class GetUserId:IGetUserId
{
public IHttpContextAccessor _contextAccessor;
private readonly AuthenticationStateProvider _authenticationStateProvider;
public GetUserId(IHttpContextAccessor contextAccessor,AuthenticationStateProvider authenticationStateProvider)
{
_contextAccessor = contextAccessor;
_authenticationStateProvider = authenticationStateProvider;
}
public  string Get()
{            
var userId = _contextAccessor.HttpContext.User.Claims.First().Value;
return userId;
}
}

那么,有没有任何安全的方法可以在.cs文件中检索经过身份验证的用户信息(例如userId(,并将其记录到数据库日志中以供用户审核日志?

首先,您应该创建一个自定义AuthenticationStateProvider

using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
namespace BlazorServerTestDynamicAccess.Services;
public class CustomAuthenticationStateProvider : RevalidatingServerAuthenticationStateProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public CustomAuthenticationStateProvider(ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory)
: base(loggerFactory) =>
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
protected override TimeSpan RevalidationInterval { get; } = TimeSpan.FromMinutes(30);
protected override async Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState, CancellationToken cancellationToken)
{
// Get the user from a new scope to ensure it fetches fresh data
var scope = _scopeFactory.CreateScope();
try
{
var userManager = scope.ServiceProvider.GetRequiredService<IUsersService>();
return await ValidateUserAsync(userManager, authenticationState?.User);
}
finally
{
if (scope is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
else
{
scope.Dispose();
}
}
}
private async Task<bool> ValidateUserAsync(IUsersService userManager, ClaimsPrincipal? principal)
{
if (principal is null)
{
return false;
}
var userIdString = principal.FindFirst(ClaimTypes.UserData)?.Value;
if (!int.TryParse(userIdString, out var userId))
{
return false;
}
var user = await userManager.FindUserAsync(userId);
return user is not null;
}
}

然后注册:

services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();

现在您可以在服务中使用它。下面是一个例子:

public class UserInfoService 
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public UserInfoService(AuthenticationStateProvider authenticationStateProvider) =>
_authenticationStateProvider = authenticationStateProvider ??
throw new ArgumentNullException(nameof(authenticationStateProvider));
public async Task<string?> GetUserIdAsync()
{
var authenticationState = await _authenticationStateProvider.GetAuthenticationStateAsync();
return authenticationState.User.Identity?.Name;
}
}

好吧,如果你不想使用AuthenticationStateProvider,并且cookie不起作用,你需要任何其他方法来验证和授权用户删除保留。

我会通过一些在预订期间管理的电子邮件+密码帐户来处理这个问题,然后以这种方式进行验证,或者只是任何";令牌";。

即使有人不想注册,当你为你的客户预订时,你也会收到他的电话或电子邮件。通过这种方式,您可以生成一些随机密码,并将其发送给客户,其中包含他需要通过电话/电子邮件登录的信息,以及管理预订所需的密码。

更简单的方法是生成一些令牌作为参数,用户可以将其与deleteURL一起使用以进行身份验证。只需将其与该令牌一起存储在数据库房间预订中即可。示例@page "/deleteRoom/{token}

然后你可以用这种方式

public async Task<int> DeleteHotelRoomAsync(string token)
{
var roomDetails = await _dbContext.HotelRooms.Where(n=>n.deleteToken == token).FirstOrDefaultAsync();
if (roomDetails == null)
{
return 0;
}
_dbContext.HotelRooms.Remove(roomDetails);
//ToDo
//_dbContext.DbLog.Add(userId,roomId);
return await _dbContext.SaveChangesAsync();
}

只需重写OnInitialized方法即可将该令牌字符串作为组件参数。

最新更新