Add project files.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
@page "/login"
|
||||
@inherits StudioComponentBase
|
||||
@layout BasicLayout
|
||||
|
||||
@* <div class="login-backdrop" style="left:0; top: 0; bottom:0; right:0; position: fixed; background-color: red; background-image: url(_content/Elsa.Studio.Login/bg.jpg); background-repeat: no-repeat; background-size: cover;"> *@
|
||||
<div class="d-flex justify-end flex-grow-1">
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.Book" Color="Color.Inherit" Href="https://v3.elsaworkflows.io/" Target="_blank" title="Documentation"/>
|
||||
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://github.com/elsa-workflows/elsa-core" Target="_blank" title="Source code"/>
|
||||
</div>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Small">
|
||||
<MudStack Spacing="10">
|
||||
<h2 class="LoginTitle">Elsa @ServerVersion</h2>
|
||||
<MudPaper Elevation="1">
|
||||
<MudGrid Spacing="0" Justify="Justify.Center">
|
||||
<MudItem md="9" xs="7" Class="pa-4 mx-auto my-4">
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.h5">Login</MudText>
|
||||
<EditForm Model="@_model" OnValidSubmit="TryLogin">
|
||||
<div class="d-flex flex-column">
|
||||
<DataAnnotationsValidator/>
|
||||
<MudTextField Label="Username" Required="true" Variant="Variant.Outlined" For="@(() => _model.Username)" @bind-Value="_model.Username" autocomplete="username"/>
|
||||
<MudTextField Label="Password" Required="true" Variant="Variant.Outlined" For="@(() => _model.Password)" @bind-Value="_model.Password" InputType="InputType.Password" autocomplete="current-password"/>
|
||||
<MudCheckBox @bind-Value="_model.RememberMe" Label="Remember me"/>
|
||||
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary" Class="mt-3 align-self-end">Login</MudButton>
|
||||
</div>
|
||||
</EditForm>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.subtitle2" Align="Align.Center" Class="mt-2">Elsa Studio @ClientVersion</MudText>
|
||||
</MudContainer>
|
||||
@* </div> *@
|
||||
@@ -0,0 +1,77 @@
|
||||
using Elsa.Studio.Contracts;
|
||||
using Elsa.Studio.Login.Contracts;
|
||||
using Elsa.Studio.Login.Pages.Login.Models;
|
||||
using Elsa.Studio.Login.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using MudBlazor;
|
||||
|
||||
namespace Elsa.Studio.Login.Pages.Login;
|
||||
|
||||
/// <summary>
|
||||
/// The login page.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
public partial class Login
|
||||
{
|
||||
private readonly LoginModel _model = new();
|
||||
|
||||
[Inject] private IJwtAccessor JwtAccessor { get; set; } = default!;
|
||||
[Inject] private ICredentialsValidator CredentialsValidator { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
||||
[Inject] private AuthenticationStateProvider AuthenticationStateProvider { get; set; } = default!;
|
||||
[Inject] private IClientInformationProvider ClientInformationProvider { get; set; } = default!;
|
||||
[Inject] private IServerInformationProvider ServerInformationProvider { get; set; } = default!;
|
||||
|
||||
private string ClientVersion { get; set; } = "3.0.0";
|
||||
private string ServerVersion { get; set; } = "3.0.0";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var clientInformation = await ClientInformationProvider.GetInfoAsync();
|
||||
var serverInformation = await ServerInformationProvider.GetInfoAsync();
|
||||
ClientVersion = clientInformation.PackageVersion;
|
||||
ServerVersion = string.Join('.', serverInformation.PackageVersion.Split('.').Take(2));
|
||||
}
|
||||
|
||||
private async Task TryLogin()
|
||||
{
|
||||
var isValid = await ValidateCredentials(_model.Username, _model.Password);
|
||||
if (!isValid)
|
||||
{
|
||||
Snackbar.Add("Invalid credentials. Please try again", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
((AccessTokenAuthenticationStateProvider)AuthenticationStateProvider).NotifyAuthenticationStateChanged();
|
||||
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("returnUrl", out var returnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(returnUrl.FirstOrDefault() ?? "", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo("", true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ValidateCredentials(string username, string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(username) && string.IsNullOrEmpty(password))
|
||||
return false;
|
||||
|
||||
var result = await CredentialsValidator.ValidateCredentialsAsync(username, password);
|
||||
|
||||
if (!result.IsAuthenticated)
|
||||
return false;
|
||||
|
||||
await JwtAccessor.WriteTokenAsync(TokenNames.AccessToken, result.AccessToken!);
|
||||
await JwtAccessor.WriteTokenAsync(TokenNames.RefreshToken, result.RefreshToken!);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
h2.LoginTitle {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Grandstander', cursive;
|
||||
font-size: 60px;
|
||||
color: #ffffff;
|
||||
opacity: 0.8;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Elsa.Studio.Login.Pages.Login.Models;
|
||||
|
||||
internal class LoginModel
|
||||
{
|
||||
public string Username { get; set; } = default!;
|
||||
public string Password { get; set; } = default!;
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user