我找到了一种在服务器端会话中存储用户数据的方法。我通过使用 CircuitHandler Id 作为用户访问系统的“令牌”来做到这一点。只有用户名和 CircuitId 存储在客户端 LocalStorage 中(使用 Blazored.LocalStorage);其他用户数据存储在服务器中。我知道这是很多代码,但这是我能找到的在服务器端保持用户数据安全的最佳方式。
UserModel.cs(用于客户端 LocalStorage)
public class UserModel
{
public string Username { get; set; }
public string CircuitId { get; set; }
}
SessionModel.cs(我的服务器端会话的模型)
public class SessionModel
{
public string Username { get; set; }
public string CircuitId { get; set; }
public DateTime DateTimeAdded { get; set; } //this could be used to timeout the session
//My user data to be stored server side...
public int UserRole { get; set; }
etc...
}
SessionData.cs(保留服务器上所有活动会话的列表)
public class SessionData
{
private List<SessionModel> sessions = new List<SessionModel>();
private readonly ILogger _logger;
public List<SessionModel> Sessions { get { return sessions; } }
public SessionData(ILogger<SessionData> logger)
{
_logger = logger;
}
public void Add(SessionModel model)
{
model.DateTimeAdded = DateTime.Now;
sessions.Add(model);
_logger.LogInformation("Session created. User:{0}, CircuitId:{1}", model.Username, model.CircuitId);
}
//Delete the session by username
public void Delete(string token)
{
//Determine if the token matches a current session in progress
var matchingSession = sessions.FirstOrDefault(s => s.Token == token);
if (matchingSession != null)
{
_logger.LogInformation("Session deleted. User:{0}, Token:{1}", matchingSession.Username, matchingSession.CircuitId);
//remove the session
sessions.RemoveAll(s => s.Token == token);
}
}
public SessionModel Get(string circuitId)
{
return sessions.FirstOrDefault(s => s.CircuitId == circuitId);
}
}
CircuitHandlerService.cs
public class CircuitHandlerService : CircuitHandler
{
public string CircuitId { get; set; }
public SessionData sessionData { get; set; }
public CircuitHandlerService(SessionData sessionData)
{
this.sessionData = sessionData;
}
public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
{
CircuitId = circuit.Id;
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
{
//when the circuit is closing, attempt to delete the session
// this will happen if the current circuit represents the main window
sessionData.Delete(circuit.Id);
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnConnectionUpAsync(circuit, cancellationToken);
}
}
登录.razor
@inject ILocalStorageService localStorage
@inject SessionData sessionData
....
public SessionModel session { get; set; } = new SessionModel();
...
if (isUserAuthenticated == true)
{
//assign the sesssion token based on the current CircuitId
session.CircuitId = (circuitHandler as CircuitHandlerService).CircuitId;
sessionData.Add(session);
//Then, store the username in the browser storage
// this username will be used to access the session as needed
UserModel user = new UserModel
{
Username = session.Username,
CircuitId = session.CircuitId
};
await localStorage.SetItemAsync("userSession", user);
NavigationManager.NavigateTo("Home");
}
启动.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddServerSideBlazor();
services.AddScoped<CircuitHandler>((sp) => new CircuitHandlerService(sp.GetRequiredService<SessionData>()));
services.AddSingleton<SessionData>();
services.AddBlazoredLocalStorage();
...
}