java - 用于强制类先决条件的java设计模式
问题描述
我想知道在施工时强制执行全类先决条件的最佳设计是什么。
让我举一个简化的例子。
我有一个代表安全字符串的类,例如密码。密码仅存储为其哈希表示。无法检查密码,而只能根据尝试的值进行检查。
class Password {
private String passwordHash;
private Password(){};
public Password(String aPassword) {
setPassword(aPassword);
}
public void setPassword(String aPassword) {
passwordHash = hash(aPassword);
}
public boolean checkPassword(String attempt) {
return verify(attempt, passwordHash);
}
}
问题是如何设计哈希算法的选择。客户端代码必须能够从不同的哈希算法中进行选择。而且,在给定的应用程序中,所有密码都必须使用相同的哈希算法。
所以,我定义了一个Hasher接口,
interface Hasher {
String hash(String password);
boolean verify(String attempt, String hash);
}
可能有不同的 Hasher 实现。
class SimpleHasher implements Hasher {
public String hash(String password) { // native java String.hashCode()
return Integer.toString(password.hashCode(),16);
}
public boolean verify(String attempt, String hash) {
return attempt.hashCode()==Integer.valueOf(hash, 16);
}
}
class SecureHasher implements Hasher {
public String hash(String password) { // Secure SCrypt hash
return com.lambdaworks.crypto.SCryptUtil.scrypt(password,16384,8,1);
}
public boolean verify(String attempt, String hash) {
return com.lambdaworks.crypto.SCryptUtil.check(attempt,hash);
}
}
客户端代码必须选择一个实现并设置散列器。在那之前,没有人可以实例化密码。并且一旦设置,哈希就无法更改。
这是设计决策。
目前,我声明了一个static private
变量,因此所有 Password 实例的哈希值都是相同的;并设置了一个强制它不能更改一次的设置器。
class Password {
static private Hasher hasher = null;
static public void setHasher(Hasher ahasher) throws Exception {
if (hasher!=null) throw new Exception("hasher cannot be changed");
hasher = ahasher;
}
....
并且构造函数确保设置了哈希
class Password {
...
public Password(String aPassword) throws Exception {
if (hasher==null) throw new Exception("no hasher set yet");
setPassword(aPassword);
}
...
到目前为止,一切都很好。但是,在我看来,它看起来不太好。我想知道是否有一些常见的模式来解决这个问题。所以我的问题是这种模式是否存在以及如何在我的案例中实现它。
解决方案
我建议更改您的设计并尝试以不同的方式处理它。首先,做一些重构。构造函数不应包含任何代码。其次,您制作哈希器的接口很棒。不过,我会将其重构为:
public interface Hash {
String hashed(String value);
boolean isValid(String hashed);
}
接下来,更改您的密码类:
public class Password {
private String password;
private Hash hash;
public Password(String password, Hash hash) {
this.password = password;
this.hash = hash;
}
public boolean isValid(String password) {
return hash.hashed(this.password).equals(hash.hashed(password);
}
}
那将是一个优雅的设计。您只需要确保通过构造函数传递正确的哈希实现。一旦设置好,每个密码都将被验证为相同的实现。
推荐阅读
- javascript - 增加材质ui的选择下拉菜单的宽度
- elasticsearch - 从 Kafka 更新 Elasticsearch 中的部分文档
- verilog - 允许在包内重新声明某些参数以进行模拟
- javascript - JS 构造函数/原型与类的语义名称
- delve - golang dlv 看不到源代码:: 没有这样的文件或目录
- javascript - 如何使用 java 脚本将 HTML 表单详细信息写入 Excel 工作表
- amazon-web-services - 当我登录到不同的图像存储库时,从哪里提取 docker 图像?
- ruby-on-rails - Ruby on Rails 项目图像显示问题 - 在网页上
- cakephp-3.0 - CakePHP 3.x - 资产添加版本而不是时间戳
- python - 为什么我的尝试除了不能正常工作?蟒蛇 3