Skip to content

Commit

Permalink
退出登录等
Browse files Browse the repository at this point in the history
  • Loading branch information
Codespilot committed Jan 10, 2024
1 parent aa47429 commit d71da6e
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 22 deletions.
49 changes: 38 additions & 11 deletions Source/Starfish.Webapp/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
@inherits LayoutComponentBase

@implements IDisposable
@attribute [Authorize]

@inject JwtAuthenticationStateProvider Authentication
@inject NavigationManager Navigation


<FluentDesignTheme Mode="DesignThemeModes.Dark" OfficeColor="OfficeColor.Office"/>
<FluentLayout>
<FluentHeader>
Expand All @@ -12,17 +16,16 @@

<FluentIcon Color="Color.Lightweight" Value="@(new Icons.Filled.Size20.Settings())"/>

<a href="/apps">
<FluentPersona Name="@(Identity?.Username ?? "starfish")" Id="persona"
ImageSize="36px"
Status="PresenceStatus.Available"
StatusSize="PresenceBadgeSize.Small"/>
</a>
<FluentPersona Name="@(Identity?.Username ?? "starfish")" Id="persona"
ImageSize="36px"
Image="https://s.gravatar.com/avatar/38a519cc759f85fc814868d0656c0c18?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Frz.png"
Status="PresenceStatus.Available"
StatusSize="PresenceBadgeSize.Small"/>
</div>
</FluentHeader>

<FluentStack Class="main" Orientation="Orientation.Horizontal" Width="100%">
<FluentNavMenu Width="360" Collapsible="true">
<FluentNavMenu Width="360" Style="height: 100%; background-color: var(--neutral-fill-stealth-rest);" Collapsible="true">
<FluentNavLink Icon="@(new Icons.Regular.Size24.Home())" Href="/" Match="NavLinkMatch.All">@(Resources.IDS_MENU_TEXT_HOME)</FluentNavLink>
<FluentNavLink Icon="@(new Icons.Regular.Size24.Apps())" Href="/apps">@(Resources.IDS_MENU_TEXT_APPS)</FluentNavLink>
@if (Identity?.IsInRole("SA") == true)
Expand All @@ -48,13 +51,15 @@

<FluentFooter>
<div class="link1">
<a href="https://www.fluentui-blazor.net" target="_blank">Documentation and demos</a>
</div>
<div class="link2">
<span>
Nerosoft © 2024. All rights reserved.
</span>
</div>
<div class="link2">
<a href="javascript:void(0);" @onclick="@OnLogoutClicked">
Logout
</a>
</div>
</FluentFooter>

<FluentToastProvider MaxToastCount="10"/>
Expand All @@ -73,6 +78,28 @@
var state = await AuthenticationState;
Identity = new UserPrincipal(state.User);
StateHasChanged();

Authentication.AuthenticationStateChanged += OnAuthenticationStateChanged;
}

private async void OnAuthenticationStateChanged(Task<AuthenticationState> task)
{
var state = await AuthenticationState;
if (state.User?.Identity?.IsAuthenticated != true)
{
Navigation.NavigateTo("/login");
}
}

private async Task OnLogoutClicked(MouseEventArgs args)
{
await Authentication.LogoutAsync();
}

public void Dispose()
{
Authentication.AuthenticationStateChanged -= OnAuthenticationStateChanged;
AuthenticationState?.Dispose();
}

}
5 changes: 5 additions & 0 deletions Source/Starfish.Webapp/Pages/Apps/Detail.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
@page "/apps/{id:long}"

<FluentBreadcrumb Style="margin-bottom: 16px;">
<FluentBreadcrumbItem Href="/">@(Resources.IDS_MENU_TEXT_HOME)</FluentBreadcrumbItem>
<FluentBreadcrumbItem Href="/apps">@(Resources.IDS_MENU_TEXT_APPS)</FluentBreadcrumbItem>
<FluentBreadcrumbItem Href="@($"/apps/{Id}")">@(Resources.IDS_BREADCRUMB_APPS_DETAIL)</FluentBreadcrumbItem>
</FluentBreadcrumb>

@code {
[Parameter]
Expand Down
33 changes: 31 additions & 2 deletions Source/Starfish.Webapp/Pages/Apps/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</FluentGridItem>
<FluentGridItem lg="12" sm="12" md="12">
<FluentDataGrid ItemsProvider="_provider" Pagination="Pagination" ItemSize="46" GenerateHeader="GenerateHeaderOption.Sticky" TGridItem="AppInfoItemDto">
<PropertyColumn Style="line-height: 32px" Title="Id" Property="@(c => c.Id)" />
<PropertyColumn Style="line-height: 32px" Title="Id" Property="@(c => c.Id)"/>
<TemplateColumn Title="Name" Align="@Align.Start">
<FluentButton Appearance="Appearance.Lightweight" OnClick="@(() => HandleDetailClicked(context.Id))">@(context.Name)</FluentButton>
</TemplateColumn>
Expand All @@ -33,6 +33,8 @@
<PropertyColumn Style="line-height: 32px" Title="Update at" Property="@(c => c.UpdateTime)"/>
<TemplateColumn Title="Actions" Align="@Align.End">
<FluentButton IconEnd="@(new Icons.Regular.Size16.Edit())" OnClick="@(() => OnEditClicked(context.Id))"/>
<FluentButton IconEnd="@(new Icons.Regular.Size16.LockClosedKey())" OnClick="@(() => OnResetSecretClicked(context.Id))"/>
<FluentButton IconEnd="@(new Icons.Regular.Size16.Delete())" OnClick="@(() => OnDeleteClicked(context.Id, context.Name))"/>
</TemplateColumn>
</FluentDataGrid>
</FluentGridItem>
Expand Down Expand Up @@ -103,7 +105,34 @@
private async Task OnEditClicked(long id)
{
var title = id == 0 ? Resources.IDS_APPS_EDIT_TITLE_ADD : Resources.IDS_APPS_EDIT_TITLE_EDIT;
await DialogService.ShowDialogAsync<Edit>(id, new DialogParameters { Title = title, Modal = true });
var dialog = await DialogService.ShowDialogAsync<Edit>(id, new DialogParameters { Title = title, Modal = true });
var result = await dialog.Result;
if (result.Cancelled)
{
await Pagination.SetCurrentPageIndexAsync(0);
}
}

private async Task OnDeleteClicked(long id, string name)
{
var message = string.Format(Resources.IDS_APPS_INDEX_REMOVE_CONFIRMATION_MESSAGE, name);
var confirmation = await DialogService.ShowConfirmationAsync(message, primaryText: Resources.IDS_COMMON_YES, secondaryText: Resources.IDS_COMMON_NO, title: Resources.IDS_APPS_INDEX_REMOVE_CONFIRMATION_TITLE);
var result = await confirmation.Result;
if (!result.Cancelled)
{
await Api.DeleteAsync(id)
.ContinueWith(task =>
{
task.WaitAndUnwrapException();
task.Result.EnsureSuccess();
});
await Pagination.SetCurrentPageIndexAsync(0);
}
}

private async Task OnResetSecretClicked(long id)
{
await DialogService.ShowDialogAsync<ResetSecret>(id, new DialogParameters { Modal = true });
}

private async Task OnSearchClicked()
Expand Down
77 changes: 77 additions & 0 deletions Source/Starfish.Webapp/Pages/Apps/ResetSecret.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
@implements IDialogContentComponent<long>

@inject IAppsApi AppsApi
@inject IToastService ToastService

<FluentDialogHeader ShowDismiss="true">
<FluentStack VerticalAlignment="VerticalAlignment.Center">
<FluentIcon Value="@(new Icons.Regular.Size24.LockClosedKey())"/>
<FluentLabel Typo="Typography.PaneHeader">
@(Resources.IDS_APPS_RESET_SECRET_DIALOG_TITLE)
</FluentLabel>
</FluentStack>
</FluentDialogHeader>

<FluentDialogBody>
<FluentStack Orientation="Orientation.Vertical">
<FluentTextField Style="width: 100%" Required="true"
Label="@(Resources.IDS_APPS_EDIT_LABEL_SECRET)"
@bind-Value="Secret"/>
<FluentLabel>@(Resources.IDS_APPS_RESET_SECRET_DIALOG_TIPS)</FluentLabel>
</FluentStack>
</FluentDialogBody>

<FluentDialogFooter>
<FluentButton Appearance="Appearance.Accent" OnClick="@SaveAsync" Loading="Loading">@(Resources.IDS_COMMON_SAVE)</FluentButton>
<FluentButton Appearance="Appearance.Neutral" OnClick="@CancelAsync">@(Resources.IDS_COMMON_CANCEL)</FluentButton>
</FluentDialogFooter>

@code {

[Parameter]
public long Content { get; set; }

[CascadingParameter]
public FluentDialog Dialog { get; set; } = default!;

private bool Loading { get; set; }

private string Secret { get; set; }

private async Task SaveAsync()
{
try
{
Loading = true;

var data = new AppInfoSetSecretDto
{
Secret = Secret
};

await AppsApi.SetSecretAsync(Content, data)
.ContinueWith(task =>
{
task.WaitAndUnwrapException();
task.Result.EnsureSuccess();
});

await Dialog.CloseAsync(Content);
}
catch (Exception exception)
{
var message = exception.GetPromptMessage();
ToastService.ShowError(message);
}
finally
{
Loading = false;
}
}

private async Task CancelAsync()
{
await Dialog.CancelAsync();
}

}
8 changes: 4 additions & 4 deletions Source/Starfish.Webapp/Pages/Team/Detail.razor
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<FluentDivider Style="width: 100%;"/>
<FluentLabel>@Data.Description</FluentLabel>
<FluentDivider Style="width: 100%;"/>
@if (Data.OwnerId != User?.GetUserIdOfInt32())
@if (Data.OwnerId != Identity?.GetUserIdOfInt32())
{
<FluentLabel>@(Resources.IDS_COMMON_OPERATIONS)</FluentLabel>
<FluentStack Orientation="Orientation.Horizontal" Wrap="true">
Expand All @@ -36,7 +36,7 @@
<FluentStack Orientation="Orientation.Horizontal" Wrap="true">
@foreach (var member in Members)
{
@if (Data.OwnerId != User?.GetUserIdOfInt32())
@if (Data.OwnerId != Identity?.GetUserIdOfInt32())
{
<FluentPersona Name="@member.NickName"
ImageSize="50px"
Expand Down Expand Up @@ -70,7 +70,7 @@
[CascadingParameter]
private Task<AuthenticationState> AuthenticationState { get; set; }

private UserPrincipal User { get; set; }
private UserPrincipal Identity { get; set; }

private TeamDetailDto Data { get; } = new();

Expand All @@ -84,7 +84,7 @@
{
var user = await AuthenticationState;

User = new UserPrincipal(user.User);
Identity = new UserPrincipal(user.User);

await LoadAsync();
}
Expand Down
2 changes: 1 addition & 1 deletion Source/Starfish.Webapp/Pages/User/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@layout EmptyLayout

@inject NavigationManager Navigation
@inject IdentityAuthenticationStateProvider Authentication
@inject JwtAuthenticationStateProvider Authentication
@inject IJSRuntime Script
@inject IToastService ToastService
@inject IIdentityApi Api
Expand Down
4 changes: 2 additions & 2 deletions Source/Starfish.Webapp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public static async Task Main(string[] args)
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
builder.Services
.AddScoped<IdentityAuthenticationStateProvider>()
.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<IdentityAuthenticationStateProvider>())
.AddScoped<JwtAuthenticationStateProvider>()
.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<JwtAuthenticationStateProvider>())
.AddCascadingAuthenticationState()
.AddBlazoredLocalStorageAsSingleton()
.AddHttpClientApi(options =>
Expand Down
12 changes: 12 additions & 0 deletions Source/Starfish.Webapp/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@
<data name="IDS_APPS_INDEX_BUTTON_ADD" xml:space="preserve">
<value>Add app</value>
</data>
<data name="IDS_APPS_INDEX_REMOVE_CONFIRMATION_MESSAGE" xml:space="preserve">
<value>Are you sure to remove this app '{0}'?</value>
</data>
<data name="IDS_APPS_INDEX_REMOVE_CONFIRMATION_TITLE" xml:space="preserve">
<value>Remove App</value>
</data>
<data name="IDS_APPS_RESET_SECRET_DIALOG_TIPS" xml:space="preserve">
<value>The system will encrypt the secret and can not be decrypted. You should keep the secret yourself. If you forget the origin secret, please reset it.</value>
</data>
<data name="IDS_APPS_RESET_SECRET_DIALOG_TITLE" xml:space="preserve">
<value>Reset secret</value>
</data>
<data name="IDS_BREADCRUMB_APPS_DETAIL" xml:space="preserve">
<value>Detail</value>
</data>
Expand Down
6 changes: 6 additions & 0 deletions Source/Starfish.Webapp/Rest/Defines/IAppsApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ internal interface IAppsApi

[Put("/api/apps/{id}")]
Task<IApiResponse> UpdateAsync(long id, [Body] AppInfoUpdateDto data, CancellationToken cancellationToken = default);

[Put("/api/apps/{id}/secret")]
Task<IApiResponse> SetSecretAsync(long id, [Body] AppInfoSetSecretDto data, CancellationToken cancellationToken = default);

[Delete("/api/apps/{id}")]
Task<IApiResponse> DeleteAsync(long id, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

namespace Nerosoft.Starfish.Webapp;

public class IdentityAuthenticationStateProvider : AuthenticationStateProvider
public class JwtAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly ILocalStorageService _storageService;

public IdentityAuthenticationStateProvider(ILocalStorageService storageService)
public JwtAuthenticationStateProvider(ILocalStorageService storageService)
{
_storageService = storageService;
}
Expand All @@ -27,6 +27,15 @@ public async Task SetAuthenticationStateAsync(string accessToken, string refresh
NotifyAuthenticationStateChanged(authState);
}

public async Task LogoutAsync()
{
await _storageService.RemoveItemAsync(Constants.LocalStorage.AccessToken);
await _storageService.RemoveItemAsync(Constants.LocalStorage.RefreshToken);

var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal()));
NotifyAuthenticationStateChanged(authState);
}

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
ClaimsIdentity identity;
Expand Down

0 comments on commit d71da6e

Please sign in to comment.