我有一个应用程序询问用户的用户名和密码。目前,对于 Unix 系统(大多数),我从 /etc/shadow
读取密码哈希。但是对于 macOS 来说要麻烦得多(他们使用自己的标准),所以我想知道是否有一种简单的方法来验证用户名和密码。
我正在考虑使用 login
为此以一种奇怪的方式编程,但这不是最好的解决方案。
我正在使用 golang,但 C 或 C++ 中的解决方案也会很有用。
编辑
@TheNextman 的答案正是我所要求的,但与其他人交谈时,他们建议我使用 PAM,因为它适用于多个操作系统。我花了一些功夫才理解它,因为我正在寻找一个简单的 API 来验证用户和密码,例如 verify(username string, password string) -> boolean
但我知道 PAM 更通用,因此更复杂。
但这是我最终使用的代码,它是在 GO 中使用 C 绑定(bind)制作的。
package Authentication
import "C"
import (
"encoding/json"
"fmt"
"github.com/vvanpo/golang-pam"
)
func ValidateUser(username, password string) (bool, error) {
// TODO correct handle of errors
UserPssword := userPassword{
Username : username,
Password : password,
}
b, _ := json.Marshal(UserPssword)
conn := myConHand{
username:C.CString(string(b)),
}
tx, _ := pam.Start("sshd", username, conn)
r := tx.Authenticate(0)
if r == pam.SUCCESS{
return true, nil
} else {
return false, nil
}
}
type userPassword struct {
Username string
Password string
}
type myConHand struct {
username *C.char
}
//C.GoString
func (m myConHand) RespondPAM(msg_style int, msg string) (string, bool) {
str := C.GoString(m.username)
var UserPssword userPassword
_ = json.Unmarshal([]byte(str), &UserPssword)
switch msg_style {
case pam.PROMPT_ECHO_OFF:
fmt.Println("Password!!")
return UserPssword.Password, true
case pam.PROMPT_ECHO_ON:
fmt.Println("Username!!")
return UserPssword.Username, true
case pam.ERROR_MSG:
fmt.Println(msg)
return "", true
case pam.TEXT_INFO:
fmt.Println(msg)
return "", true
default:
return "", true
}
}
它有一些问题,例如我正在使用
/etc/pam.d/sshd
服务,因为我知道我将使用的计算机具有相同的服务,但我不知道哪个操作系统具有 /etc/pam.d/sshd
,另一种选择是创建我自己的服务,但我必须为我发现的每个不同的标准创建一个服务 3 Linux PAM、openPAM (macos) 和 Solaris PAM。但总的来说,我认为这是一个强大的解决方案,因为我正在重用现有的身份验证机制。
最佳答案
a solution in C or C++ would be useful too
这是使用 CoreServices 的 C 语言示例.为简洁起见,省略了错误和结果检查:
void on_logon(const char* username, const char* password) {
CSIdentityQueryRef query;
CFArrayRef idArray = NULL;
CSIdentityRef result;
CFStringRef cfUsername = NULL;
CFStringRef cfPassword = NULL;
cfUsername = CFStringCreateWithCString(NULL, username, kCFStringEncodingUTF8);
query = CSIdentityQueryCreateForName(kCFAllocatorDefault, cfUsername, kCSIdentityQueryStringEquals, kCSIdentityClassUser, CSGetDefaultIdentityAuthority());
CSIdentityQueryExecute(query, kCSIdentityQueryGenerateUpdateEvents, NULL);
idArray = CSIdentityQueryCopyResults(query);
if (CFArrayGetCount(idArray) != 1)
{
// Username didn't match...
}
result = (CSIdentityRef) CFArrayGetValueAtIndex(idArray, 0);
cfPassword = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8);
if (CSIdentityAuthenticateUsingPassword(result, cfPassword))
{
// Username and password are valid!!
}
CFRelease(cfUsername);
CFRelease(idArray);
CFRelease(cfPassword);
CFRelease(query);
}
关于macos - 如何以编程方式在 macOS 上验证用户和密码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59956598/