Сценарий применения
Программа WPF была разработана с использованием Prism 8, а кодировка выполнена в форме MVVM. Когда программа запустится, сначала войдите в интерфейс входа для выполнения аутентификации. После успешной аутентификации откроется главное окно программы.
Идея реализации проекта
После того, как программный фреймворк WPF собран, в программе сохраняется Shell.xaml
, что эквивалентно единственной стадии исполнителя. Форма входа в систему (далее именуемая LoginView
) и основная форма компоновки программы (далее именуемая MainView
) соответственно управляются IRegionManager
, и представления последовательно воспроизводятся в разное время по мере необходимости. Все операции выполняются с помощью соответствующего кода ViewModel
.
- При запуске программы оболочка активирует
LoginView
через ViewModel и с помощью методаAdd RegionManager
. После операции входа в систему отправляется сообщение loginState message. Сообщение отправляется через пользовательский класс отправки сообщений и подписки (определенный в программе:LoginSentEvent
). - Оболочка принимает
loginState
, переданноеLoginSentEven
, для получения сообщения об успешном входе в систему. Если вход в систему прошел успешно, используйте метод деактивацииRegionManager
, чтобы сделатьLoginView
неактивным. Используйте метод добавления, чтобы активировать представлениеMainView
. Если авторизация не увенчается успехом, View не поменяется, и останется на странице ввода логина. Identity
иPrincipal
объекты. Документация , Пример использования. В .NET объектыIdentity
иPrincipal
тесно связаны с безопасностью. ОбъектIdentity
представляет идентификатор пользователя и метод, используемый для аутентификации пользователя. ОбъектPrincipal
, с другой стороны, представляет контекст безопасности пользователя, от имени которого выполняется код, включая идентификатор этого пользователя (Identity
).В C# вы можете получить доступ к объектуIdentity
через интерфейсSystem.Security.Principal.IIdentity
, который определяет базовую функциональность объекта идентификации. Доступ к объектуPrincipal
возможен черезSystem.Security.Principal.IPrincipal
интерфейс, который определяет базовую функциональность principal объекта.Вы можете использовать эти объекты для аутентификации пользователей и выполнения проверок авторизации в вашем приложении. Оба объекта могут быть использованы в приложении для аутентификации пользователей и создания контекстов безопасности для пользовательских сеансов. МодульSessionAuthenticationModule
хранит маркер безопасности, участника, идентификаторы в файле cookie и кэше в памяти, чтобы избежать повторных вызовов службы аутентификации.
Основная реализация проекта
Процедура создания программы Prism описываться не будет. Это не является предметом внимания данной статьи.
1.Логика взаимодействия App.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class App { protected override Window CreateShell() { return Container.Resolve<Shell>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IAuthenticationService, AuthenticationService>(); } protected override void OnStartup(StartupEventArgs e) { UserPrincipial userPrincipial = new UserPrincipial(); AppDomain.CurrentDomain.SetThreadPrincipal(userPrincipial); base.OnStartup(e); } } |
2. Shell.xaml View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<Window x:Class="LoginRoleApp.Views.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prism="http://prismlibrary.com/" xmlns:local="clr-namespace:LoginRoleApp.Views" prism:ViewModelLocator.AutoWireViewModel="True" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" WindowStartupLocation="CenterScreen" mc:Ignorable="d" Title="{Binding Title}" Height="450" Width="800"> <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <i:InvokeCommandAction Command="{Binding LoadDataCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> <Grid> <ContentControl prism:RegionManager.RegionName ="MainRegion"/> </Grid> </Window> |
Shell.xaml
использует EventTrigger для привязки метода LoadDataCommand
путем ссылки на System.Windows.Interactivity
, так что он может выполнять соответствующие операции при реализации представления, загруженного в VM
3. Shell ViewModel
Метод loaddata() запускается после загрузки представления и выполняет несколько действий:
1.MainRegion
зарегистрирован
2.Созданы экземпляры Login
и MainWindow
,
3.Для активации добавлен LoginView
.
4. EventAggregator
используется для принятия сообщения о входе в систему и реализации метода обработки сообщений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public class ShellViewModel:BindableBase { private IEventAggregator _eventAggregator; IContainerExtension _container; private IRegionManager _regionManager; private IRegion _region; private Login loginView; private Main mainView; private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private DelegateCommand _loadDataCommand; public DelegateCommand LoadDataCommand => _loadDataCommand ?? (_loadDataCommand = new DelegateCommand(ExecuteLoadDataCommand )); public ShellViewModel(IRegionManager regionManager, IContainerExtension container,IEventAggregator aggregator) { _regionManager = regionManager; _container = container; _eventAggregator = aggregator; _eventAggregator.GetEvent<LoginSentEvent>().Subscribe(MessageReceived); } void MessageReceived(bool loginState) { if (loginState) { _region.Deactivate(loginView); mainView = _container.Resolve<Main>(); _region.Add(mainView); Title = "Now is the main form of the program"; } else { _region.Deactivate(mainView); Title = "User Login"; _region.Activate(loginView); } } void ExecuteLoadDataCommand() { _region = _regionManager.Regions["MainRegion"]; loginView = _container.Resolve<Login>(); Title = "User Login"; _region.Add(loginView); } } |
4. Класс публикации и подписки событий входа в систему
1 2 3 4 |
public class LoginSentEvent : PubSubEvent<bool> { } |
5. Login /LoginViewModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<UserControl x:Class="LoginRoleApp.Views.Login" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid Margin="30"> <Grid.RowDefinitions> <RowDefinition Height="0.8*"/> <RowDefinition Height="0.7*"/> </Grid.RowDefinitions> <DockPanel Grid.Row="1" Width="300"> <StackPanel Margin="30 10 30 0" DockPanel.Dock="Top"> <TextBlock Text="{Binding Message}" Foreground="Red" FontSize="10"/> <TextBlock Text="Войдите в свой аккаунт" FontFamily="Arial Black" HorizontalAlignment="Center" FontSize="17" FontWeight="Bold"/> <TextBox Text="{Binding Login}" Margin="0 20 0 0" /> <PasswordBox Name="password" Margin="0 20 0 0" /> <Button Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=password}" Content="Войти" Margin="10,20,0,0" Width="180"/> </StackPanel> </DockPanel> </Grid> </UserControl> |
VM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public class LoginViewModel : BindableBase { private IEventAggregator _eventAggregator; private IAuthenticationService _authentication; private string _login; public string Login { get { return _login; } set { SetProperty(ref _login, value); } } private string message = ""; public string Message { get { return message; } set { SetProperty(ref message, value); } } public LoginViewModel(IEventAggregator aggregator,IAuthenticationService authentication) { _eventAggregator = aggregator; _authentication = authentication; } private DelegateCommand<PasswordBox> _loginCommand; public DelegateCommand<PasswordBox> LoginCommand => _loginCommand ?? (_loginCommand = new DelegateCommand<PasswordBox>(ExecuteLoginCommand)); void ExecuteLoginCommand(PasswordBox password) { try { var user = _authentication.AuthenticateUser(Login, password.Password); UserPrincipial userPrincipial = Thread.CurrentPrincipal as UserPrincipial; if (userPrincipial == null) throw new ArgumentException("Не зарегистрирован пользователь по умолчанию!"); userPrincipial.UserIdentity = new UserIdentity(user.Login,user.FIO,user.Role.ToString()); Login = ""; password.Password = ""; _eventAggregator.GetEvent<LoginSentEvent>().Publish(true); } catch (Exception ex) { Message = ex.Message; } } } |
После входа в систему с помощью кнопки «Войти», отправляется сообщение через _eventAggregator.GetEvent<LoginSentEvent>().Publish(true);
После того, как ShellViewModel
принимает сообщение, вызывается метод MessageReceived
, который скрывает представление входа в систему и активирует основное представление.
MainWindow не имеет к этому никакого отношения, это элемент управления окном UserControl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<UserControl x:Class="LoginRoleApp.Views.Main" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" xmlns:local="clr-namespace:LoginRoleApp.Common" prism:ViewModelLocator.AutoWireViewModel="True"> <UserControl.Resources> <local:RoleToVisibilityConverter x:Key="RoleToVisibilityConverter" /> </UserControl.Resources> <StackPanel> <TextBlock Text="{Binding UserAuth}"/> <TextBlock Text="{Binding UserRole}"/> <TextBlock Text="Этот текст только для администратора" Foreground="Green" Visibility="{Binding UserRole, Converter={StaticResource RoleToVisibilityConverter}, ConverterParameter=Администратор}"/> <Button Command="{Binding LogoutCmd}" Content="Выйти" Margin="10,20,0,0" Width="180"/> </StackPanel> </UserControl> |
vm Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class MainViewModel : BindableBase { private string userAuth; public string UserAuth { get { return userAuth; } set { SetProperty(ref userAuth, value); } } private string userRole; public string UserRole { get { return userRole; } set { SetProperty(ref userRole, value); } } IEventAggregator _eventAggregator; private DelegateCommand _logoutcmd; public DelegateCommand LogoutCmd => _logoutcmd ?? (_logoutcmd = new DelegateCommand(ExecuteLogoutCommand)); private void ExecuteLogoutCommand() { bool loginState = false; if (_eventAggregator != null) _eventAggregator.GetEvent<LoginSentEvent>().Publish(loginState); } public MainViewModel(IEventAggregator aggregator) { _eventAggregator = aggregator; UserAuth = Thread.CurrentPrincipal.Identity.Name; UserRole = Thread.CurrentPrincipal.IsInRole("Admin")?"Администратор":"Пользователь"; } } |