【问题标题】:How to resolve Xamarin iOS SecKeyChain InteractionNotAllowed issue?如何解决 Xamarin iOS SecKeyChain InteractionNotAllowed 问题?
【发布时间】:2018-10-25 04:27:46
【问题描述】:

在我的 Xamarin.iOS 项目中,我使用 SecRecord/SecKeyChain 来存储我的令牌值和应用程序版本。从生产日志中,当尝试在钥匙串中写入/读取项目时,我发现状态码为“InteractionNotAllowed”的钥匙串相关异常。 Apple 文档指出,要解决 InteractionNotAllowed 错误,我们需要将默认 kSecAttrAccessible 属性值从“WhenUnlocked”更改为“Always”。 但是在我现有的代码中,当我将可访问属性更改为“Always”时,应用程序会注销,因为它无法从钥匙串中读取令牌。读取时返回“Item not found”。但是当我再次尝试保存令牌时,它返回“重复项”。所以我再次尝试删除相同的项目,但这次它再次返回“找不到项目”。真的很奇怪,我不能删除它,我不能用同一个键读取它。

下面是代码sn-p -

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;
        }

任何帮助都会很棒!谢谢

【问题讨论】:

    标签: ios objective-c xamarin xamarin.forms xamarin.ios


    【解决方案1】:

    属性Service也是我们使用KeyChain存储或检索数据时的唯一标识。你没有发布你的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() 中编写了一个硬代码(该服务已被编写为一个常量),如果您想检索您的值,您还应该在方法@987654330 中将Service 设置为App.AppName @。

    读取时返回“未找到项目”。但是当我试图保存令牌时 再次返回“重复项”。

    这是因为当我们使用相同的Account但不同的Service检索数据时,KeyChain找不到对应的SecRecord。这让您认为SecRecord 不存在,然后使用相同的Account 来存储价值。 Duplicate item 结果抛出。对于 SecRecordAccountService 都必须是唯一的。

    【讨论】:

    • -谢谢。我没有在 GetValueFromAccountAndKey 函数的任何地方使用键值。 (传递密钥以避免Android中的构建错误。它是通过依赖服务调用的共享代码)。我更新了我的获取价值代码供您参考。我也使用了相同的服务名称。当我在 CreateRecordForNewKeyValue 和 ExistingRecordForKey 函数中添加 Accessible = SecAccessible.Always 时出现问题。
    • @Vishnu 我用了你的GetValueFromAccountAndKey (),可以检索存储的数据。然后如果我写一个新值,旧记录将被删除。 Here 是我的示例,效果很好。我错过了什么吗?
    • @Land Lu - MSFT 在代码中做一件事,请在“ExistingRecordForKey”和“CreateRecordForNewKeyValue”函数中注释或删除“Accessible = SecAccessible.Always”。然后运行代码并保存一个数据。现在在两个函数中添加“Accessible = SecAccessible.Always”并运行代码。尝试读取已保存的数据。这次我相信会发生这种奇怪的行为。
    • 你能重现这个问题吗?
    • 我测试你上面说的,评论Accessible = SecAccessible.Always。但是使用我的示例,读写都可以很好地工作。
    猜你喜欢
    • 2019-03-29
    • 2016-03-08
    • 2020-07-22
    • 2022-11-06
    • 2018-09-24
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多