Hi,@António Albuquerque,For your questions:
How to I say to the blazor app that we are now authenticated
--You could try NotifyAuthenticationStateChanged method
and then using HttpContext.SignInAsync to sign in that user (using cookie based auth here). Is this correct
--You should avoid it ,you would interact with server via signalr instead of http in Blazor,For detailed reason,please check this document
The other question is where do I store the access tokens I receive after login
--Create a scoped service to hold the tokens,follow this document(Notice the authentication service is for MVC part as documented)
If you just want authenticate in a razor component,a minimal example:
public class AuthenticationService
{
public event Action<ClaimsPrincipal>? UserChanged;
private ClaimsPrincipal? currentUser;
public ClaimsPrincipal CurrentUser
{
get { return currentUser ?? new(); }
set
{
currentUser = value;
if (UserChanged is not null)
{
UserChanged(currentUser);
}
}
}
}
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private AuthenticationState authenticationState;
public CustomAuthenticationStateProvider(AuthenticationService service)
{
authenticationState = new AuthenticationState(service.CurrentUser);
service.UserChanged += (newUser) =>
{
authenticationState = new AuthenticationState(newUser);
NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(newUser)));
};
}
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(authenticationState);
}
public class TokenProvider
{
public string? accesstoken { get; set; }
public string? refreshtoken { get; set; }
}
public class UserProfile
{
public string? UserName { get; set; }
//other claims....
}
register the services:
builder.Services.AddScoped<AuthenticationService>();
builder.Services.AddScoped<TokenProvider>();
builder.Services.AddScoped<AuthenticationStateProvider,
CustomAuthenticationStateProvider>();
builder.Services.AddHttpClient("Auth", op =>
{
op.BaseAddress = new Uri("target uri");
});
razor component:
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
</Authorized>
<NotAuthorized>
<div>
Email:<input @bind="email" />
</div>
<div>
Password: <input type="password" @bind="password" />
</div>
<div>
<button @onclick="SignIn">Sign in</button>
</div>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
@code {
public string email = string.Empty;
public string password = string.Empty;
private async Task SignIn()
{
var httpclient = httpclientfactory.CreateClient("Auth");
var response = await httpclient.PostAsJsonAsync("/account/login", new { email = email, password = password });
if (response.IsSuccessStatusCode)
{
tokenprovider = await response.Content.ReadFromJsonAsync<TokenProvider>();
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenprovider.accesstoken);
var userprofile = await httpclient.GetFromJsonAsync<UserProfile>("/profile");
//add some check here
var identity = new ClaimsIdentity(
new[]
{
new Claim(ClaimTypes.Name, userprofile.UserName),
},
"Custom Authentication");
var newUser = new ClaimsPrincipal(identity);
AuthenticationService.CurrentUser = newUser;
}
}
}
Result:
If you want to keep your authentication state for a long time,you may check this document related and this part of document
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.
Best regards,
Ruikai Feng