感谢Magoo先生的回答,我已经开始工作了。该解决方案是通过事件完成的,并且也显示在官方示例项目FlightFinder中。
确保使用singleton
:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<LoginService, ILoginService>();
}
public event Action OnChange;
public async Task<bool> LoginFromLocalStorageAsync()
{
var response = await _http.PostJsonAsync<TokenResult>("/api/auth", model);
Token = response.Token;
ExpireDate = response.ExpireDate;
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
OnChange?.Invoke(); // Here we invoke the event
}
protected override void OnInit()
{
LoginService.OnChange += StateHasChanged;
}
我目前正在尝试学习火焰。我有一个具有多个链接的NavMenu
组件,其中一个是<a href="login">Login</a>
,该链接应在用户登录后立即更改为<a onclick="@Logout">Logout</a>
。登录发生在另一个组件中({ {1}}组件)使用我自己的服务Login
。
LoginService
具有无记名令牌的LoginService
属性和属性Token
。我试图在剃刀视图中使用带有public bool IsLoggedIn => !string.IsNullOrEmpty(Token);
语句的简单绑定。那没有用,我的下一次尝试是在有人登录后立即在if-else
组件中使用StateHasChanged();
。也没有用(可能是因为我想更新Login
,然后不是NavMenu
...)
Login
@inject ILoginService LoginService
@if(LoginService.IsLoggedIn) {
<a href="logout">Logout</a>
}
else {
<a href="login">Login</a>
}
<form onsubmit="@Submit">
<input type="email" placeholder="Email Address" bind="@LoginViewModel.Email" />
<input type="password" placeholder="Password" bind="@LoginViewModel.Password" />
<button type="submit">Login</button>
</form>
@functions
{
public LoginViewModel LoginViewModel { get; } = new LoginViewModel();
public async Task Submit()
{
await LoginService.LoginAsync(LoginViewModel);
}
}
很遗憾,public class LoginService : ILoginService
{
private readonly HttpClient _http;
public LoginService(HttpClient http) => _http = http;
public string Token { get; private set; }
public bool IsLoggedIn => !string.IsNullOrEmpty(Token);
public async Task<bool> LoginAsync(LoginViewModel model)
{
try
{
var response = await _http.PostJsonAsync<TokenResult>("/api/auth", model);
Token = response.Token;
return true;
}
catch (Exception)
{
return false;
}
}
}
停留在NavMenu
上。我正在考虑从<a href="login">Login</a>
组件向NavMenu
发送消息。如何获得Login
来更新其视图?
答案 0 :(得分:0)
您可以将一个事件添加到LoginService中,每当令牌更改时都会引发该事件。
然后,您的菜单组件可以预订该事件(您已经注入了LoginService)并调用StateHasChanged()。
这将刷新视图并更新客户端。
答案 1 :(得分:0)
您不应使用表单元素,也不应提交表单。 幸运的是,据我所知,内部Blazor代码应使用preventDefault()停止提交。 无论如何,回发发生后可能会调用LoginAsync。只需考虑一下:一方面,您的代码启动了一个“回发”,另一方面,它向服务器发出了一个http请求。简而言之,您应该使用HttpClient发布表单数据。
表单数据:
<div>
<input type="email" placeholder="Email Address" bind="@LoginViewModel.Email" />
<input type="password" placeholder="Password" bind="@LoginViewModel.Password" />
<button type="button">Login</button>
</div>
请注意,按钮的type属性应设置为“ button”。现在,每当您按下按钮时,都会调用LoginAsync方法,您将从中将登录数据发布到服务器。
尝试以下操作:
将这些代码段添加到您的LoginService中:
[Inject]
protected LocalStorage localStorage;
// Note: LocalStorage is a library for storing data in Web Storage API. You may store your token in the LocalStorage, and retrieve it when you need to verify whether a user is authenticated.
// This method may be called from your NavMenu Component
public bool IsAuthenticated()
{
var token = localStorage.GetItem<string>("token");
return (token != null);
}
public async Task<bool> LoginAsync(LoginViewModel model)
{
try
{
var response = await _http.PostJsonAsync<TokenResult>("/api/auth", model);
Token = response.Token;
if (Token)
{
// Save the JWT token in the LocalStorage
// https://github.com/BlazorExtensions/Storage
await localStorage.SetItem<Object>("token", Token);
// Returns true to indicate the user has been logged // in and the JWT token is saved on the user browser
return true;
}
}
catch (Exception)
{
return false;
}
}
最后是NavMenu.cshtml:
@inject ILoginService LoginService
@if(LoginService.IsAuthenticated()) {
<a href="logout">Logout</a>
}
else {
<a href="login">Login</a>
}
//您还必须在客户端上设置Startup类,如下所示:
public void ConfigureServices(IServiceCollection services)
{
// Add Blazor.Extensions.Storage
// Both SessionStorage and LocalStorage are registered
// https://github.com/BlazorExtensions/Storage
**services.AddStorage();**
...
}
//一般来说,这就是您必须在客户端上执行的操作。 //在服务器上,您必须有一个方法,例如在Account控制器中,该方法的功能是生成JWT令牌,您必须配置JWT中间件,以为控制器添加必要的属性,例如实例:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
希望这对您有帮助...