【问题标题】:How to check user's device in iOS SDK如何在 iOS SDK 中检查用户的设备
【发布时间】:2019-01-17 09:35:23
【问题描述】:

我正在尝试修复我的应用程序中的Sim Swap 问题。我想要一种独特的方式来识别用户的电话。所以尝试了以下情况

  • 我知道我们无法通过以下链接从用户设备获取手机 IMEI 和其他信息

Link1Link2

  • 我可以使用 identifierForVendor,但它也会随着应用程序的每次安装而变化。

  • 第三种选择是使用DeviceCheck API 来识别设备,但它仅在 iOS 11 中提供。

请告诉我如何识别用户设备和临时禁用用户的帐户以防 Sim Swap。

【问题讨论】:

标签: ios


【解决方案1】:

您必须将 UUID 保留在钥匙串中,因为在卸载应用后钥匙串数据仍然存在

iOS 将钥匙串信息作为敏感信息进行管理。您可以使用 SwiftKeychainWrapper 库可轻松访问您的钥匙串。

apple doc 关于 SIM 更改的内容:https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo

编码示例:

let uuid = UIDevice.current.identifierForVendor?.uuidString
KeychainWrapper.standard.set(uuid, forKey: "appUUID")

只要您想获取 appUUID,只需从钥匙串中获取:

let uuid = KeychainWrapper.standard.string(forKey: "appUUID")

注意:您还可以检查您的UUID是否在重新安装后更改 应用程序并将其更新为钥匙串。

【讨论】:

    【解决方案2】:

    一个可接受的解决方案是生成一个唯一的 UUID 并将其保存到 Keychain,即使在应用程序删除后 Keychain 项仍然存在,

    
    /* DeviceUID.h
    #import <Foundation/Foundation.h>
    
    @interface DeviceUID : NSObject
    + (NSString *)uid;
    @end
    */
    
    
    // Device.m
    #import "DeviceUID.h"
    
    @import UIKit;
    
    @interface DeviceUID ()
    
    @property(nonatomic, strong, readonly) NSString *uidKey;
    @property(nonatomic, strong, readonly) NSString *uid;
    
    @end
    
    @implementation DeviceUID
    
    @synthesize uid = _uid;
    
    #pragma mark - Public methods
    
    + (NSString *)uid {
        return [[[DeviceUID alloc] initWithKey:@"deviceUID"] uid];
    }
    
    #pragma mark - Instance methods
    
    - (id)initWithKey:(NSString *)key {
        self = [super init];
        if (self) {
            _uidKey = key;
            _uid = nil;
        }
        return self;
    }
    
    /*! Returns the Device UID.
        The UID is obtained in a chain of fallbacks:
          - Keychain
          - NSUserDefaults
          - Apple IFV (Identifier for Vendor)
          - Generate a random UUID if everything else is unavailable
        At last, the UID is persisted if needed to.
     */
    - (NSString *)uid {
        if (!_uid) _uid = [[self class] valueForKeychainKey:_uidKey service:_uidKey];
        if (!_uid) _uid = [[self class] valueForUserDefaultsKey:_uidKey];
        if (!_uid) _uid = [[self class] appleIFV];
        if (!_uid) _uid = [[self class] randomUUID];
        [self save];
        return _uid;
    }
    
    /*! Persist UID to NSUserDefaults and Keychain, if not yet saved
     */
    - (void)save {
        if (![DeviceUID valueForUserDefaultsKey:_uidKey]) {
            [DeviceUID setValue:self.uid forUserDefaultsKey:_uidKey];
        }
        if (![DeviceUID valueForKeychainKey:_uidKey service:_uidKey]) {
            [DeviceUID setValue:self.uid forKeychainKey:_uidKey inService:_uidKey];
        }
    }
    
    #pragma mark - Keychain methods
    
    /*! Create as generic NSDictionary to be used to query and update Keychain items.
     *  param1
     *  param2
     */
    + (NSMutableDictionary *)keychainItemForKey:(NSString *)key service:(NSString *)service {
        NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init];
        keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
        keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
        keychainItem[(__bridge id)kSecAttrAccount] = key;
        keychainItem[(__bridge id)kSecAttrService] = service;
        return keychainItem;
    }
    
    /*! Sets
     *  param1
     *  param2
     */
    + (OSStatus)setValue:(NSString *)value forKeychainKey:(NSString *)key inService:(NSString *)service {
        NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
        keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding];
        return SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL);
    }
    
    + (NSString *)valueForKeychainKey:(NSString *)key service:(NSString *)service {
        OSStatus status;
        NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
        keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
        keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
        CFDictionaryRef result = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainItem, (CFTypeRef *)&result);
        if (status != noErr) {
            return nil;
        }
        NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result;
        NSData *data = resultDict[(__bridge id)kSecValueData];
        if (!data) {
            return nil;
        }
        return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }
    
    #pragma mark - NSUserDefaults methods
    
    + (BOOL)setValue:(NSString *)value forUserDefaultsKey:(NSString *)key {
        [[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
        return [[NSUserDefaults standardUserDefaults] synchronize];
    }
    
    + (NSString *)valueForUserDefaultsKey:(NSString *)key {
        return [[NSUserDefaults standardUserDefaults] objectForKey:key];
    }
    
    #pragma mark - UID Generation methods
    
    + (NSString *)appleIFA {
        NSString *ifa = nil;
        Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager");
        if (ASIdentifierManagerClass) { // a dynamic way of checking if AdSupport.framework is available
            SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");
            id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector);
            SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier");
            NSUUID *advertisingIdentifier = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector);
            ifa = [advertisingIdentifier UUIDString];
        }
        return ifa;
    }
    
    + (NSString *)appleIFV {
        if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {
            // only available in iOS >= 6.0
            return [[UIDevice currentDevice].identifierForVendor UUIDString];
        }
        return nil;
    }
    
    + (NSString *)randomUUID {
        if(NSClassFromString(@"NSUUID")) {
            return [[NSUUID UUID] UUIDString];
        }
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
        CFRelease(uuidRef);
        NSString *uuid = [((__bridge NSString *) cfuuid) copy];
        CFRelease(cfuuid);
        return uuid;
    }
    
    @end
    

    来源: https://medium.com/@miguelcma/persistent-cross-install-device-identifier-on-ios-using-keychain-ac9e4f84870f

    【讨论】:

    • 只有链接答案不好,因为它们在不久的将来可能会失效所以-1
    猜你喜欢
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多