我使用的是修补版本的NameAndPassword,如下所示:https://github.com/skycocker/NameAndPassword
当在登录窗口之外使用此功能时(例如system.login.screensaver或我自己的测试权限),仅使用NameAndPassword插件,按下Ok或取消后,窗口将挂起约10秒。
添加一些日志后,我看到插件上调用了MechanismDestroy,并发布了NameAndPassword,但它从未在NameAndPassword中解除锁定。我也没有看到PluginDestroy被调用。在调用MechanismDestroy后,安全代理会再挂10秒。
我看到了这个相关的帖子:SecurityAgentPlugin不再在Yosemite上工作(SFAuthorizationPluginView)
但遵循接受的答案不起作用,根据授权插件参考,不应该调用didDeactivate(没有对RequestInterrupt的调用,也从未调用MechanismDeactivate)。调用SetResult应该足够了。
我可以通过从视野中打开窗户并强行关闭来破解它,但必须有办法让它按预期工作。
我发现了不同的破解方法——我得到了auth机制实例的引用计数,并释放了除最后一个之外的所有实例。在setResult调用之后执行此操作。这就解决了问题。不应该是这样的,但苹果并没有给我们太多的选择。
如果我的回复对某人没有帮助,我也遇到了同样的问题,找到了不同的方法(不干净,甚至相当脏),因为我无法使提出的解决方案发挥作用。如果标识符有效,我会销毁窗口(我会测试它们)。类似地,如果标识符无效,则窗口仍然存在。
- (void)buttonPressed:(SFButtonType)inButtonType
{
NSString *userNameString;
NSString *passwordString;
userNameString = mUserName;
passwordString = [mPPasswordSecureTextField stringValue];
// if the OK button was pressed, write the identity and credentials and allow authorization,
// otherwise, if the cancel button was pressed, cancel the authorization
if (inButtonType == SFButtonTypeOK)
{
const char *puserName = [userNameString UTF8String];
const char *ppassword = [passwordString UTF8String];
AuthorizationValue userNameValue = { strlen(puserName) + 1, (char*)puserName };
AuthorizationValue userPasswordValue = { strlen(ppassword) + 1, (char*)ppassword };
// add the username and password to the context values
[self callbacks]->SetContextValue([self engineRef], kAuthorizationEnvironmentUsername, 1, &userNameValue);
[self callbacks]->SetContextValue([self engineRef], kAuthorizationEnvironmentPassword, 1, &userPasswordValue);
// allow authorization
[self callbacks]->SetResult([self engineRef], kAuthorizationResultAllow);
// to know if we must close the window
// try to auth with the provided user and pswd
BOOL status = [self macosTestLogin: puserName with: ppassword];
if(status == YES)
{
// the user and pwd are good, we can close the window
NSView* v;
// if we are in sleep, screensaver and lock mode (don't work in loggin mode,
// but don't be sad loggin mode have a workaround in config authdb,
// the setting is shared true)
if (mUseIPView) {
v = mPasswordView;
NSWindow* w = [v window];
[w close];
}
}
// suggested workaround (don't work)
[self didDeactivate];
}
else if (inButtonType == SFButtonTypeCancel)
{
// cancel authorization
[self callbacks]->SetResult([self engineRef], kAuthorizationResultUserCanceled);
}
}
以及测试功能:
- (BOOL) macosTestLogin: (const char *)userName with: (const char *)password
{
// hack to know if we must close the window
// try to auth with the provided user and pswd
AuthorizationRef authorization = NULL;
AuthorizationItem items[2];
items[0].name = kAuthorizationEnvironmentPassword;
items[0].value = (char*) password;
items[0].valueLength = strlen(password);
items[0].flags = 0;
items[1].name = kAuthorizationEnvironmentUsername;
items[1].value = (char*) userName;
items[1].valueLength = strlen(userName);
items[1].flags = 0;
AuthorizationRights rights = {2, items};
AuthorizationEnvironment enviroment = {2, items};
// creates a new authorization reference and provides an option to authorize or preauthorize rights.
AuthorizationCreate(NULL, &enviroment, kAuthorizationFlagDefaults, &authorization);
AuthorizationFlags flag = kAuthorizationFlagDefaults| kAuthorizationFlagExtendRights;
OSStatus status = AuthorizationCopyRights(authorization, &rights, &enviroment, flag, NULL);
if(status == errAuthorizationSuccess)
{
return YES;
}
return NO;
}
这对我来说很有效,我只在"屏幕保护程序"模式下这样做,登录时选项shared=true就足够了。