连接到VPN始终询问密码

时间:2015-12-02 11:20:39

标签: ios swift vpn keychain

我正在尝试使用NETWORK EXTENSION框架连接VPN,但它始终要求我输入密码。我不知道为什么因为看起来好像从Keychain成功了,也许我错了。这是我的代码:

func createVPN() {
        let manager: NEVPNManager = NEVPNManager.sharedManager()
        let keychain = KeychainSwift()

        manager.loadFromPreferencesWithCompletionHandler { (error: NSError?) -> Void in
            if (error != nil) {
                print("error")
            } else {
                let p = NEVPNProtocolIKEv2()
                p.remoteIdentifier = "*******"
                p.username = "*******"
                p.passwordReference = keychain.getData("vpnpassword")!
                p.serverAddress = "free-nl.hide.me"
                p.authenticationMethod = NEVPNIKEAuthenticationMethod.None
                p.useExtendedAuthentication = true
                p.disconnectOnSleep = false
                manager.`protocol` = p
                manager.enabled = true
                manager.saveToPreferencesWithCompletionHandler({ (error: NSError?) -> Void in
                    if (error != nil) {
                        print(error)
                    } else {
                        do {
                            try NEVPNManager.sharedManager().connection.startVPNTunnel()
                        } catch {
                            print("can't connect VPN'")
                        }
                    }
                })
            }
        }
    }

P.S。当我自己输入密码时,它可以正常工作。

而且我也无法理解为什么createVPN函数只有在从viewDidLoad调用时才有效,这种方式不是:

@IBAction func initVPN(sender: AnyObject) {
   self.createVPN()
}

SOLUTION:

问题出在Keychain

解决方案是使用objc函数来保存和获取数据:

+ (void) storeData: (NSString * )key data:(NSData *)data {
    NSLog(@"Store Data");
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:data forKey:(__bridge id)kSecValueData];

    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
    if(errSecSuccess != status) {
        NSLog(@"Unable add item with key =%@ error:%d",key,(int)status);
    }
}

+ (NSData *) getData: (NSString *)key {
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];

    CFTypeRef result = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);

    if( status != errSecSuccess) {
        NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
        return nil;
    }

    NSData *resultData = (__bridge NSData *)result;
    return resultData;
}

0 个答案:

没有答案