坚持用户凭据在WPF瓦特/团结和MVVM [英] Persisting user credentials in WPF w/Unity and MVVM

查看:135
本文介绍了坚持用户凭据在WPF瓦特/团结和MVVM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不在乎有做过一个Windows应用程序类似具有这种可怕的去了。我工作的一个WPF应用程序(棱镜,团结,MVVM)和我刚刚完成了登录视图。一旦用户的凭据已经过验证对SQL Server表我这样做:

I am having a terrible go at this despite having done something similar in a Windows Application. I am working on a WPF application (Prism, Unity, MVVM) and I have just completed the login view. Once the user's credentials have been validated against a table in SQL Server I do this:

 Thread.CurrentPrincipal = user.GenericPrincipal();

用户类的定义是这样的:

The user class is defined as such:

public class ApplicationIdentity : GenericIdentity, IApplicationIdentity
{
    public string UserName { get; set; }
    public bool Authenticated { get; set; }

    public ICollection<IModuleProperties> Modules { get; set; }
    public ICollection<IViewProperties> Views { get; set; }

    public ApplicationIdentity(string userName, IAuthenticatedUser authenticatedUser)
        : base(userName)
    {
        UserName = userName;
        Authenticated = authenticatedUser.Authenticated;
        Modules = authenticatedUser.Modules;
        Views = authenticatedUser.Views;
    }

    public IPrincipal GenericPrincipal()
    {
        return new GenericPrincipal(this, null);
    }
}



我遇到的问题是后立即登录屏幕被驳回我拨打这个电话:

The problem I am running into is that almost immediately after the login screen is dismissed I make this call:

 var currentUser = (IApplicationIdentity)Thread.CurrentPrincipal.Identity;



会抛出一个异常的身份无法转换为类型IApplicationIdentity,我不知道是什么我失踪。所有到目前为止,解决此我看了SO /谷歌的文章都通过验证对广告用户解决了这个问题,但是,这并不在我的情况下工作。

Which throws an exception that Identity can't be cast to type IApplicationIdentity, and I am not sure what I am missing. All of the SO / Google articles I have read so far around this have all solved this problem by authenticating the user against AD, but that doesn't work in my scenario.

我想在这里解决的问题很简单,就是坚持当前登录的用户,哪些模块和浏览他们应该有机会获得。如果有更好的方式来实现这一目标设定CurrentPrincipal之外,我其他的解决方案完全开放。 !谢谢你也许可以提供任何帮助。

The problem I am trying to solve here is simply to persist the currently logged on user and which Modules and Views they should have access to. If there is a better way to achieve this outside of setting the CurrentPrincipal I am completely open to other solutions. Thanks for any help you might be able to provide!

修改(液):

我只想结束对什么解决办法是循环。下面是一个有点教程,所以这是一个有点冗长,但应该是有帮助的任何人穿过它绊脚石。接受答案建议我注射团结容器,注册我的对象的实例,并从那里使用它。我同意,这可能是正确的做法,但它在我的引导程序有点要求我黑客。之前,我的引导程序逻辑虽然,我也许应该去上有点麻烦的准备工作。

I just want to close the loop on what the solution was. What follows is a bit of tutorial, so it is a bit lengthy but should be helpful to anyone stumbling across it. The accepted answer suggested that I inject the Unity container, register an instance of my object, and work with it from there. I agree that this is probably the correct approach, but it required me to "hack" on my Bootstrapper a bit. Before I get to the Bootstrapper logic though, I should probably go over a bit of the prep work involved.

在我原来的做法我登录看法是不符合我的容器中注册,因为登录观点之前,我跑实例引导程序(App.xaml中打开登录查看。)

In my original approach my Login view was not registered with my container, because the Login view was instantiated prior to my Bootstrapper running (App.xaml opened the Login view.)

这是我做的第一件事就是让我的查看和视图模型注射ALA:

The first thing that I did was make my View and ViewModel injectable ala:

    public Login(ILoginViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }

    public LoginViewModel(IUnityContainer container)
    {
        Container = container;
    }



还是那句话:这应该是熟悉的人已经使用Unity(或国际奥委会合作一般来说)。然后,我需要用统一登记我目前的用户对象一旦用户已经验证:

Again: this should be familiar to anyone that has worked with Unity (or IoC in general). I then needed to register my current user object with Unity once a user had been authenticated:

    private void Login(object obj)
    {
        ...
        if (user.Authenticated)
        {
            Container.RegisterInstance("CurrentUser", user); 
        }
        ...
    }



任何人都已经跟随任何在互联网上比比皆是的棱镜/统一/ MVVM文章可能是熟悉下面的方法:

Anyone that has followed any of the Prism/Unity/MVVM articles that abound on the internet is probably familiar with the following method:

    protected override IModuleCatalog CreateModuleCatalog()
    {
        var catalog = new ModuleCatalog();
        catalog.AddModule(typeof (CoreModule));
        catalog.AddModule(typeof (CoreModule2));
        catalog.AddModule(typeof (CoreModule3));
        return catalog;
    }

这方法简单明了,但在现实世界中的场景模块用户访问将可能是动态的而不是静态的(或两者的组合。) CreateModuleCatalog()被称为引导程序运行()提前 InitializeShell()。在我来说,我仍然有所有用户都将有机会获得(不考虑授权级别),但(在我看来)一个静态的模块,它会觉得反patternish从这个方法实例化登录视图(更不用提寄存器类型使用Unity)因此,我的 CreateModuleCatalog()变成了:

This method is straightforward enough, but in a real world scenario the modules a user has access to will probably be dynamic rather than static (or a combination of both.) CreateModuleCatalog() is called in the Bootstrapper Run() method ahead of InitializeShell(). In my case I still have a static module that all users would have access to (regardless of authorization level), but (in my opinion) it would feel "anti-patternish" to instantiate the Login view from this method (not to mention register the types with Unity.) Thus my CreateModuleCatalog() became:

    protected override IModuleCatalog CreateModuleCatalog()
    {
        var catalog = new ModuleCatalog();
        catalog.AddModule(typeof(CoreModule));
        return catalog;
    }



我选择了用我的的覆盖InitializeShell() 注册我的登录类型,显示登录视图等我最终清盘与此一个实现:

I opted to use my override of InitializeShell() to register my Login types, display the Login view, etc. I ultimately wound up with this for an implementation:

    protected override void InitializeShell()
    {
        base.InitializeShell();
        Container.RegisterType(typeof (Login), "LoginView");
        Container.RegisterType<ILoginViewModel, LoginViewModel>();

        Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
        ShowLogOn();

        Application.Current.MainWindow = (Window)Shell;
        Application.Current.MainWindow.Show();
    }



ShowLogOn()将关闭,如果用户最终命中取消的登录视图按钮,这样我可以很可能放在所有的代码从应用ShowLogOn()之前调用了 base.InitializeShell(),这样不必要的代码无法运行。 ShowLogOn()看上去完全像你想象它看起来:

ShowLogOn() will Shutdown the application if the user eventually hits the Cancel button on the Login view, so I could have probably placed all of the code from ShowLogOn() up prior to the call to base.InitializeShell() so that needless code isn't run. ShowLogOn() looks exactly like you might expect it to look:

    private void ShowLogOn()
    {
        var login = Container.Resolve<Login>();
        var dialogResult = login.ShowDialog();

        if (!dialogResult.Value)
        {
            Application.Current.Shutdown(1);
        }
        else
        {
            LoadAuthorizedModules();
            Application.Current.MainWindow = null;
            Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        }
    }

如果用户取消了我的登录查看对话框结果将是虚假和应用程序关闭。如果已成功验证,虽然,我们现在需要加载,他们被允许看到的模块。这也很简单:

If the user cancels out of my Login view the dialog result will be false and the application is shutdown. If they have successfully authenticated though, we now need to load the modules that they are permitted to see. This is also pretty straightforward:

    private void LoadAuthorizedModules()
    {
        var currentUser = Container.Resolve<IApplicationIdentity>("CurrentUser");
        foreach (var module in currentUser.Modules)
        {
            var moduleAssembly = Assembly.Load(module.AssemblyName);
            var loadingModule = moduleAssembly.GetType(module.Type);

            ModuleCatalog.AddModule(new ModuleInfo
                {
                    ModuleName = loadingModule.Name,
                    ModuleType = loadingModule.AssemblyQualifiedName
                });
        }
    }

这方法值得进一步的解释。首先来看看这条线,因为它可能会造成混乱: VAR的currentUser = Container.Resolve< IApplicationIdentity>(的currentUser); 注意,我并没有明确注册类型 IApplicationIdentity 在我的代码的任何地方!它,然而,含蓄我这样做的时候注册: Container.RegisterInstance(的currentUser,用户); 技术上我可以写上一语句: Container.RegisterInstance< IApplicationIdentity>(的currentUser,用户); 但是这是多余的我,所以做什么都你觉得最舒服。

This method warrants a bit more explanation. First take a look at this line as it might be confusing: var currentUser = Container.Resolve<IApplicationIdentity>("CurrentUser"); notice that I did not explicitly register the type IApplicationIdentity anywhere in my code! It was, however, implicitly registered when I did this: Container.RegisterInstance("CurrentUser", user); technically I could have written the previous statement as: Container.RegisterInstance<IApplicationIdentity>("CurrentUser", user); but that is redundant to me so do what ever you feel most comfortable with.

IApplicationIdentity 的模块属性包含包含有关模块信息的当前用户有权访问对象的集合。 module.AssemblyName 是我的自定义模块类型住在和 module.Type 是物理程序集的名称模块的类型。

The Modules property of IApplicationIdentity contains a collection of objects that contain information about modules the current user has access to. module.AssemblyName is the name of the physical assembly that my custom module type lives in, and module.Type is the Type of the module.

正如你可以看到:曾经的类型已经通过反射的功率负载,我们需要将它添加到统一Bootstrappers ModuleCatalog 属性,它是直线前进。假设一切已经正确,执行应该回到你的InitializeShell方法,以及壳牌现在应该启动。

As you can see: once the type has been loaded through the power of reflection, we need to add it to the Unity Bootstrappers ModuleCatalog property which is straight forward. Assuming everything has gone correctly, execution should return to your InitializeShell method, and your Shell should now start up.

这是相当漫长的,但我希望有人认为它有用。另外,我有兴趣如何使这个代码更好的任何意见。谢谢!

This was pretty lengthy, but I hope that someone finds it useful. Also, I would be interested in any opinions on how to make this code "better". Thanks!

推荐答案

您可以检查出这个问题,如果你想将其存储在线程 - 的http://stackoverflow.com/a/6699699/1798889 。但是,如果你只是想有机会获得IApplicationIdentity。我建议你刚刚注册的团结这个实例

You can check out this question if you want to store it in the thread - http://stackoverflow.com/a/6699699/1798889. But if you just want to have access to the IApplicationIdentity. I would suggest you just register that instance with unity.

// IUnityContainer can be injected by unity 
IUnityContainer container;

// Register this instance each time now you call for IApplicationIdentity this object will be returned
container.RegisterInstance(typeof (IApplicationIdentity), user.GenericPrincipal());



有了这个,现在你可以注入IApplicationIdentity和统一将在每次你需要它的时间完成它。您不必担心线程。

With this now you can inject IApplicationIdentity and unity will fulfill it each time you need it. You don't need to worry about the threads.

这篇关于坚持用户凭据在WPF瓦特/团结和MVVM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆