创建具有关系值的签名字段是最佳做法吗?

Is it best practice to create signature fields with relation values?

一家商店有顾客。每个客户都使用他们的用户 ID 和密码登录商店。

我想创建一个 Alloy 函数 (fun),当传递凭据(用户 ID 和密码)时,returns 拥有这些凭据的客户:

fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
    ???
}

我说服自己,要做到这一点,我必须这样声明客户签名:

sig Customer {
    credentials: UserID lone -> lone Password
}

通过这样创建签名,我可以这样实现功能:

fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
    credentials.password.userID
}

如果我这样创建客户签名:

sig Customer {
    userID: UserID,
    password: Password
}

那我就实现不了这个功能了。你同意吗?

我逐渐相信,设计具有关系值(例如 credentials: UserID lone -> lone Password)而不是集合(例如 userID: UserID)的值的签名字段总是更好。你也有同样的信念吗?

下面是我的Alloy模型:

sig UserID {}
sig Password {}
sig Customer {
    credentials: UserID lone -> lone Password
} 

fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
    credentials.password.userID
}

run {}

fact Every_customer_has_a_different_password_userID {
    // Every customer has a different userID
    no disj c, c': Customer | 
        c.credentials.Password = c'.credentials.Password
    // Every customer has one userID/password pair
    all c: Customer |
        one id: UserID |
            one p: Password |
                c.credentials = id -> p
}

我不同意,您可以使用集合理解来轻松检索具有给定 ID 和密码作为参数的客户集合。

看看这个模型(我冒昧地没有假设每个客户都有不同的密码("password123" 太常见了 ;-))。

sig UserID {}
sig Password {}
sig Customer {
    id :disj UserID,
    password: Password
} 

fun customerWithTheseCredentials[userID: UserID, pass: Password]: Customer {
    {c:Customer| c.id=userID and c.password=pass}
}

run {}

好吧,这是我工作的领域,所以我无法展示一个密码不会被更小心处理的例子:-)我知道这只是一个例子,但人们死于不安全的密码模型! (我喜欢这种夸张。)作为模块化狂热者,我还认为您应该将身份验证任务与客户检索分开,它们本质上不是耦合的,因此应该分开。

因此我的模型是:

sig UserId, PasswordDigest {}
sig Password { digest : disj PasswordDigest }

sig Customer {
    identity : disj UserId
}

one sig Authenticator {
    db : UserId lone -> one PasswordDigest
}

pred authenticate[ id : UserId, password : Password ] {
    password.digest in Authenticator.db[id]
}

fun customerWithTheseCredentials[ userid: UserId, password : Password ] : lone Customer {
    authenticate[ userid, password ] => identity.userid else none
}

run { #Customer = 3 and #Password=3}