在我的Xamarin.iOS项目中,我使用SecRecord / SecKeyChain来存储我的令牌值和应用版本。从生产日志中,我在尝试写入/读取钥匙串中的项目时,发现了与钥匙串相关的异常,状态代码为“InteractionNotAllowed”。 Apple文档声明要解决InteractionNotAllowed错误,我们需要将默认的kSecAttrAccessible属性值从“ WhenUnlocked ”更改为“始终”。 但是在我的现有代码中,当我将可访问属性更改为“始终”时,应用程序会退出,因为它无法从钥匙串中读取令牌。阅读时会返回“找不到项目”。但是当我再次尝试保存令牌时,它会返回“重复项”。所以我再次尝试删除相同的项目,但这次又返回“找不到项目”。这真的很奇怪,我无法删除它,我无法用相同的密钥读取它。
以下是代码段 -
private SecRecord CreateRecordForNewKeyValue(string accountName, string value)
{
return new SecRecord(SecKind.GenericPassword)
{
Service = App.AppName,
Account = accountName,
ValueData = NSData.FromString(value, NSStringEncoding.UTF8),
Accessible = SecAccessible.Always //This line of code is newly added.
};
}
private SecRecord ExistingRecordForKey(string accountName)
{
return new SecRecord(SecKind.GenericPassword)
{
Service = App.AppName,
Account = accountName,
Accessible = SecAccessible.Always //This line of code is newly added.
};
}
public void SetValueForKeyAndAccount(string value, string accountName, string key)
{
var record = ExistingRecordForKey(accountName);
try
{
if (string.IsNullOrEmpty(value))
{
if (!string.IsNullOrEmpty(GetValueFromAccountAndKey(accountName, key)))
RemoveRecord(record);
return;
}
// if the key already exists, remove it before set value
if (!string.IsNullOrEmpty(GetValueFromAccountAndKey(accountName, key)))
RemoveRecord(record);
}
catch (Exception e)
{
//Log exception here -("RemoveRecord Failed " + accountName, e,);
}
//Adding new record values to keychain
var result = SecKeyChain.Add(CreateRecordForNewKeyValue(accountName, value));
if (result != SecStatusCode.Success)
{
if (result == SecStatusCode.DuplicateItem)
{
try
{
//Log exception here -("Error adding record: {0} for Account-" + accountName, result), "Try Remove account");
RemoveRecord(record);
}
catch (Exception e)
{
//Log exception here -("RemoveRecord Failed after getting error SecStatusCode.DuplicateItem for Account-" + accountName, e);
}
}
else
throw new Exception(string.Format("Error adding record: {0} for Account-" + accountName, result));
}
}
public string GetValueFromAccountAndKey(string accountName, string key)
{
try
{
var record = ExistingRecordForKey(accountName);
SecStatusCode resultCode;
var match = SecKeyChain.QueryAsRecord(record, out resultCode);
if (resultCode == SecStatusCode.Success)
{
if (match.ValueData != null)
{
string valueData = NSString.FromData(match.ValueData, NSStringEncoding.UTF8);
if (string.IsNullOrEmpty(valueData))
return string.Empty;
return valueData;
}
else if (match.Generic != null)
{
string valueData = NSString.FromData(match.ValueData, NSStringEncoding.UTF8);
if (string.IsNullOrEmpty(valueData))
return string.Empty;
return valueData;
}
else
return string.Empty;
}
}
catch (Exception e)
{
// Exception logged here -("iOS Keychain Error for account-" + accountName, e);
}
return string.Empty;
}
任何帮助都会很棒!谢谢
答案 0 :(得分:1)
当我们使用 KeyChain 存储或检索数据时,属性Service
也是唯一标识。您没有发布GetValueFromAccountAndKey()
方法,因此我们不知道key
用于什么?但在您的情况下,您应该使用相同的Service
来检索值:
string GetValueFromAccountAndKey(string accoundName, string service)
{
var securityRecord = new SecRecord(SecKind.GenericPassword)
{
Service = service,
Account = accoundName
};
SecStatusCode status;
NSData resultData = SecKeyChain.QueryAsData(securityRecord, false, out status);
var result = resultData != null ? new NSString(resultData, NSStringEncoding.UTF8) : "Not found";
return result;
}
由于您只是在CreateRecordForNewKeyValue()
中创建了一个硬代码(服务已被写为常量),如果您想要检索您的值,您还应将Service
设置为{{1} }方法App.AppName
。
返回'项目未找到'阅读时但是当我试图保存令牌时 再次返回'重复项目'。
这是因为当我们使用相同的GetValueFromAccountAndKey()
但不同的Account
来检索数据时,KeyChain无法找到相应的Service
。这使您认为SecRecord
不存在,然后使用相同的SecRecord
来存储值。抛出Account
结果。对于Duplicate item
,SecRecord
和Account
必须都是唯一的。