使用 Nhibernate 将依赖项注入域模型类(ASP.NET MVC + IOC)
我正在构建一个 ASP.NET MVC 应用程序,该应用程序使用 DDD(域驱动设计)方法,并由 NHibernate 处理数据库访问。我有域模型类(管理员),我想通过 IOC 容器(例如 Castle Windsor)将依赖项注入到其中,如下所示:
public class Administrator
{
public virtual int Id { get; set; }
//.. snip ..//
public virtual string HashedPassword { get; protected set; }
public void SetPassword(string plainTextPassword)
{
IHashingService hasher = IocContainer.Resolve<IHashingService>();
this.HashedPassword = hasher.Hash(plainTextPassword);
}
}
我基本上想为 SetPassword 方法注入 IHashingService ,而不直接调用 IOC 容器(因为这是假设成为 IOC 反模式)。但我不确定如何去做。我的 Administrator 对象要么通过 new Administrator(); 实例化,要么通过 NHibernate 加载,那么我如何将 IHashingService 注入到 Administrator 类中?
再想一想,我处理这件事的方式正确吗?我希望避免我的代码库中充斥着……
currentAdmin.Password = HashUtils.Hash(password, Algorithm.Sha512);
,而是让域模型本身来处理散列并将其整齐地封装起来。我可以想象另一位开发人员意外地选择了错误的算法,并将一些密码设置为 Sha512,一些设置为 MD5,一些使用一种盐,一些使用不同的盐等等。相反,如果开发人员正在编写...
currentAdmin.SetPassword(password);
...那么会隐藏这些细节并解决上面列出的问题,不是吗?
I'm building an ASP.NET MVC application that uses a DDD (Domain Driven Design) approach with database access handled by NHibernate. I have domain model class (Administrator) that I want to inject a dependency into via an IOC Container such as Castle Windsor, something like this:
public class Administrator
{
public virtual int Id { get; set; }
//.. snip ..//
public virtual string HashedPassword { get; protected set; }
public void SetPassword(string plainTextPassword)
{
IHashingService hasher = IocContainer.Resolve<IHashingService>();
this.HashedPassword = hasher.Hash(plainTextPassword);
}
}
I basically want to inject IHashingService for the SetPassword method without calling the IOC Container directly (because this is suppose to be an IOC Anti-pattern). But I'm not sure how to go about doing it. My Administrator object either gets instantiated via new Administrator();
or it gets loaded via NHibernate, so how would I inject the IHashingService into the Administrator class?
On second thoughts, am I going about this the right way? I was hoping to avoid having my codebase littered with...
currentAdmin.Password = HashUtils.Hash(password, Algorithm.Sha512);
...and instead get the domain model itself to take care of hashing and neatly encapsulate it away. I can envisage another developer accidently choosing the wrong algorithm and having some passwords as Sha512, and some as MD5, some with one salt, and some with a different salt etc. etc. Instead if developers are writing...
currentAdmin.SetPassword(password);
...then that would hide those details away and take care of those problems listed above would it not?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这里已经有类似的问题了:
NHibernate 对象的依赖注入
DI/IoC、NHibernate 并帮助让它们协同工作< /a>
您需要使用拦截器。查看 Fabio Maulo 的实施帖子:
https:// nhibernate.info/blog/2008/12/12/entities-behavior-injection.html
There are already similar questions here on SO:
Dependency injection with NHibernate objects
DI/IoC, NHibernate and help in getting them to work together
You'll need to use Interceptors. Take a look at Fabio Maulo's post for implementation:
https://nhibernate.info/blog/2008/12/12/entities-behavior-injection.html
您需要记住它是如何被散列的。这样您就可以在将来对字符串进行哈希处理,以检查并查看它是否是他们的密码,并将其与哈希值进行比较。这意味着您需要在对象中存储枚举或其他一些字段,以指示数据库中使用的哈希机制。
否则,如果您更改默认的散列实现,所有旧的散列密码都不再有效,并且您的用户将摸不着头脑,不明白为什么他们的密码不再有效 - 并且您最终会得到一个
IHashingService
接口不提供灵活性(因为如果不添加奇怪的规则(例如“为 2010 年 1 月 12 日之前创建的管理员使用此哈希”),就无法更改哈希实现),其存在没有真正的充分理由。为此,我将添加适当的字段(枚举、IHashingService 接口返回的字符串等),并且让 NHibernate 通过 IUserType 为我实例化哈希服务> 实现,或者我会使用工厂模式,其中具体实例由 IoC 容器提供给工厂。这将把 Jarrett 的方法级注入与一个解决方案相结合,该解决方案允许重新水化对象找到其哈希实现,而无需依赖于 IoC 容器。
祝你好运!
You need to remember how it was hashed. This is so that you can hash a string in the future to check and see if it's their password, comparing that with the hashed value. That means that you need to store an enum or some other field in your object that indicates the hashing mechanism that was used in your database.
Otherwise, if you change your default hashing implementation, all of your old hashed passwords are no longer good, and your users will be left scratching their heads as to why their passwords no longer work--and you'll end up an
IHashingService
interface that provides no flexibility (since the hashing implementation cannot be changed without adding weird rules like "use this hash for Administrators created before 2010-01-12"), existing for no real good reason.To that end, I would add the appropriate field (an enum, a string returned by the
IHashingService
interface, something) and either have NHibernate instantiate the hashing service for me via anIUserType
implementation, or I'd use a factory pattern where the concrete instances were provided to the factory by the IoC container. This would be combining Jarrett's method-level injection with a solution that allows re-hydrated objects to find their hashing implementations without being dependent on the IoC container.Good luck!
是否有原因导致您无法在
Administrator
类的构造函数中传递IHashingService
?这就是我解决依赖性的方法。编辑 #1
如果从模型中提取,请尝试使用方法级注入。
编辑 #2
另外,为什么不让自己轻松一点,直接在字符串上进行扩展呢?
虽然我确实意识到使用依赖注入有一个“可替换”的代码方面,但这对于这个例子来说并不是什么大问题。您实际上并不需要 IPasswordEncryptionService,就像您需要 ICreditCardAuthorizationService 一样。如果有一天,您将哈希算法从 SHA256 更改为 SHA512,那么数据库中的每个密码现在都会失效。
Is there a reason that you can't pass the
IHashingService
in the constructor for theAdministrator
class? That's how I would resolve the dependency.Edit #1
If pulling from a model, try using method-level injection.
Edit #2
Also, why not make it easy on yourself and just make an extension on string?
While I do realize that there's a "replaceable" code aspect of using dependency injection, this isn't exactly a big deal for this example. You don't really need a IPasswordEncryptionService the same way you'd need a, say, ICreditCardAuthorizationService. If, someday, you change your hashing algorithm from SHA256 to SHA512, you will now have invalidated every password in your database.
在应用程序外观(如果您使用任何)中对密码进行哈希处理,或者在每次调用
Administrator.SetPassword(..)
时提供IHashingService
实现。我认为这被称为双重调度?!如果您坚持DI-in-entity解决方案,我已经通过在实体上声明
[Configurable]
属性,使用PostSharp AOP和PostSharp4Spring做了类似的事情,但解决方案是对于Spring.Net。您可以在此处查看更多信息。另外,如果您从 DI 容器配置 NHibernate,则可能会陷入在容器完成配置之前尝试 DI 实体的递归。您需要一个简单的静态类,其中包含方法来在容器初始化期间抑制实体构造上的 DI。但目前无法提供示例:(Either hash the password in an application façade (if you are using any) or supply the
IHashingService
implementation on every call toAdministrator.SetPassword(..)
. I think it was called double dispatch?!If you insist on DI-in-entity solution, I have done something like that with PostSharp AOP and PostSharp4Spring by declaring
[Configurable]
attribute on the entity, but the solution is for Spring.Net. You can look here for more info. Also, if you are configuring NHibernate from the DI container, you can fall in a recursion trying to DI an entity before the container has finished configuring. You need a simple static class with method to suppress DI on entity construction during container initialization. Cannot provide an example a the moment though :(