如何解决Xamarin iOS SecKeyChain InteractionNotAllowed问题? [英] How to resolve Xamarin iOS SecKeyChain InteractionNotAllowed issue?
问题描述
在我的Xamarin.iOS项目中,我使用SecRecord/SecKeyChain来存储令牌值和应用程序版本.从生产日志中,当尝试在钥匙串中写入/读取项目时,我发现了状态码为'InteractionNotAllowed'的钥匙串相关异常. Apple文档指出,要解决InteractionNotAllowed错误,我们需要将默认的kSecAttrAccessible属性值从" WhenUnlocked "更改为"始终". 但是在我现有的代码中,当我将可访问性属性更改为"始终"应用时,由于该应用无法从钥匙串读取令牌而注销.读取时返回"未找到项目".但是,当我尝试再次保存令牌时,它会返回"重复项".因此,我再次尝试删除相同的项目,但是这次它再次返回"未找到项目".真是奇怪,我无法删除它,也无法使用相同的键来读取它.
In my Xamarin.iOS project I used SecRecord/SecKeyChain to store my token values and app version. From production log I found keychain related exceptions with status code 'InteractionNotAllowed' when try to write/read items in keychain. Apple documents states that to resolve InteractionNotAllowed error we need to change the default kSecAttrAccessible attribute value from ‘WhenUnlocked' to ‘Always’. But in my existing code when I changed accessible attribute to 'Always' app log out because it failed to read token from keychain. It return’s 'Item not found' when read. But when I tried to save token again it returns 'Duplicate item'. So again I tried to remove same item but this time it again returns 'Item not found'. That’s really strange I can’t delete it and I can’t read it with same key.
下面是代码段-
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;
}
任何帮助都会很棒!谢谢
Any help would be great! Thanks
推荐答案
当我们使用 KeyChain 存储或检索数据时,属性Service
也是唯一的标识.您没有发布GetValueFromAccountAndKey()
方法,因此我们不知道key
的用途是什么?但在您的情况下,应使用相同的Service
来检索值:
The property Service
is also an unique identification when we store or retrieve data using KeyChain. You didn't post your GetValueFromAccountAndKey()
method, so we don't know what is the key
used for? But in your case, you should use the same Service
to retrieve value:
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()
中编写了一个硬代码(服务已被编写为常量),因此,如果要检索值,还应在方法App.AppName
>.
Since you just make a hard code in your CreateRecordForNewKeyValue()
( the Service has been written as a constant ), if you want to retrieve your value you should also set the Service
as App.AppName
in the method GetValueFromAccountAndKey()
.
读取时返回找不到项目".但是当我尝试保存令牌时 再次返回重复项".
It return’s 'Item not found' when read. But when I tried to save token again it returns 'Duplicate item'.
这是因为当我们使用相同的Account
但不同的Service
来检索数据时,KeyChain无法找到相应的SecRecord
.这使您以为SecRecord
不存在,然后使用相同的Account
来存储值. Duplicate item
结果抛出.对于SecRecord
,Account
和Service
都必须是唯一的.
This is because when we use the same Account
but different Service
to retrieve data, KeyChain can't find the corresponding SecRecord
. This made you thought the SecRecord
didn't exist, then use the same Account
to store value. The Duplicate item
result throws out. For a SecRecord
, the Account
and Service
must both be unique.
这篇关于如何解决Xamarin iOS SecKeyChain InteractionNotAllowed问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!