2012-12-10 34 views
0

大家。如何將iphone用戶集成到當前系統中

我得到了一個傳統的系統,通過經典的用戶名/密碼模式對用戶進行身份驗證。 現在我需要從這個系統提供數據到iPhone App。這個應用程序會發送給我設備ID(UDID)。

我的問題是:如何將現有的用戶帳戶連接到這些UDID?有沒有讓用戶告訴我「這是我的UDID,我的帳戶是XXXX」的策略?

這些都是情況下,我可以像:

  1. 首先用戶通過PC在網絡上創建賬戶,那麼他/她轉而使用iPhone應用程序。
  2. 用戶只需使用iPhone應用程序,絕對不要在Web服務器上創建帳戶。

其實我不想強制用戶在這個系統上創建帳戶。但如果他/她這樣做了,我需要通過某種方式來識別他/她。

感謝您的任何想法。

+0

另一件我想知道的事情是:如果有人知道我的UDID(它印在我手機的背面......),那麼他可以把http請求放到服務器上,服務器永遠不會知道他是一個山寨,因爲不需要密碼。這是一個安全缺口嗎? –

+0

使用UDID是錯誤的,蘋果會拒絕它! –

+0

必須有一些方法來識別用戶,如何劑量蘋果要做到這一點?或者我已經完成了,我只是不知道? –

回答

0

你可以使用OpenUDID項目來製作你自己的UDID,然後它非常簡單,如果用戶有一個帳戶只是使用同步按鈕(所以它不覺得作爲一個登錄),每次問他的帳戶用戶啓動應用程序,搜索數據庫中的設備ID,如果存在,則將其登錄,如果您不創建帳戶並給他一些帳戶檢索選項,那麼您使用的模式非常容易出錯。

我真的建議你檢查www.parse.com相反,它會保存在當前用戶會話的緩存,這樣它從來沒有登陸,它將處理設備跨平臺的在一個更優雅的和靈活的方式

#import <Foundation/Foundation.h> 

// 
// Usage: 

// #include "OpenUDID.h" 
// NSString* openUDID = [OpenUDID value]; 
// 

#define kOpenUDIDErrorNone   0 
#define kOpenUDIDErrorOptedOut  1 
#define kOpenUDIDErrorCompromised 2 

@interface Countly_OpenUDID : NSObject { 
} 
+ (NSString*) value; 
+ (NSString*) valueWithError:(NSError**)error; 
+ (void) setOptOut:(BOOL)optOutValue; 

@end 


#if __has_feature(objc_arc) 
#error This file uses the classic non-ARC retain/release model; hints below... 
    // to selectively compile this file as non-ARC, do as follows: 
    // https://img.skitch.com/20120717-g3ag5h9a6ehkgpmpjiuen3qpwp.png 
#endif 

#import "Countly_OpenUDID.h" 
#import <CommonCrypto/CommonDigest.h> // Need to import for CC_MD5 access 
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 
#import <UIKit/UIPasteboard.h> 
#import <UIKit/UIKit.h> 
#else 
#import <AppKit/NSPasteboard.h> 
#endif 


#define OpenUDIDLog(fmt, ...) 
//#define OpenUDIDLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 
//#define OpenUDIDLog(fmt, ...) NSLog((@"[Line %d] " fmt), __LINE__, ##__VA_ARGS__); 

static NSString * kOpenUDIDSessionCache = nil; 
static NSString * const kOpenUDIDKey = @"OpenUDID"; 
static NSString * const kOpenUDIDSlotKey = @"OpenUDID_slot"; 
static NSString * const kOpenUDIDAppUIDKey = @"OpenUDID_appUID"; 
static NSString * const kOpenUDIDTSKey = @"OpenUDID_createdTS"; 
static NSString * const kOpenUDIDOOTSKey = @"OpenUDID_optOutTS"; 
static NSString * const kOpenUDIDDomain = @"org.OpenUDID"; 
static NSString * const kOpenUDIDSlotPBPrefix = @"org.OpenUDID.slot."; 
static int const kOpenUDIDRedundancySlots = 100; 

@interface Countly_OpenUDID (Private) 
+ (void) _setDict:(id)dict forPasteboard:(id)pboard; 
+ (NSMutableDictionary*) _getDictFromPasteboard:(id)pboard; 
+ (NSString*) _generateFreshOpenUDID; 
@end 

@implementation Countly_OpenUDID 

// Archive a NSDictionary inside a pasteboard of a given type 
// Convenience method to support iOS & Mac OS X 
// 
+ (void) _setDict:(id)dict forPasteboard:(id)pboard { 
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR  
    [pboard setData:[NSKeyedArchiver archivedDataWithRootObject:dict] forPasteboardType:kOpenUDIDDomain]; 
#else 
    [pboard setData:[NSKeyedArchiver archivedDataWithRootObject:dict] forType:kOpenUDIDDomain]; 
#endif 
} 


// Retrieve an NSDictionary from a pasteboard of a given type 
// Convenience method to support iOS & Mac OS X 
// 
+ (NSMutableDictionary*) _getDictFromPasteboard:(id)pboard { 
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 
    id item = [pboard dataForPasteboardType:kOpenUDIDDomain]; 
#else 
    id item = [pboard dataForType:kOpenUDIDDomain]; 
#endif 
    if (item) { 
     @try{ 
      item = [NSKeyedUnarchiver unarchiveObjectWithData:item]; 
     } @catch(NSException* e) { 
      OpenUDIDLog(@"Unable to unarchive item %@ on pasteboard!", [pboard name]); 
      item = nil; 
     } 
    } 

    // return an instance of a MutableDictionary 
    return [NSMutableDictionary dictionaryWithDictionary:(item == nil || [item isKindOfClass:[NSDictionary class]]) ? item : nil]; 
} 


// Private method to create and return a new OpenUDID 
// Theoretically, this function is called once ever per application when calling [OpenUDID value] for the first time. 
// After that, the caching/pasteboard/redundancy mechanism inside [OpenUDID value] returns a persistent and cross application OpenUDID 
// 
+ (NSString*) _generateFreshOpenUDID { 

    NSString* _openUDID = nil; 

    // August 2011: One day, this may no longer be allowed in iOS. When that is, just comment this line out. 
    // March 25th 2012: this day has come, let's remove this "outlawed" call... 
#if TARGET_OS_IPHONE  
// if([UIDevice instancesRespondToSelector:@selector(uniqueIdentifier)]){ 
//  _openUDID = [[UIDevice currentDevice] uniqueIdentifier]; 
// } 
#endif 
    // Next we generate a UUID. 
    // UUIDs (Universally Unique Identifiers), also known as GUIDs (Globally Unique Identifiers) or IIDs 
    // (Interface Identifiers), are 128-bit values guaranteed to be unique. A UUID is made unique over 
    // both space and time by combining a value unique to the computer on which it was generated—usually the 
    // Ethernet hardware address—and a value representing the number of 100-nanosecond intervals since 
    // October 15, 1582 at 00:00:00. 
    // We then hash this UUID with md5 to get 32 bytes, and then add 4 extra random bytes 
    // Collision is possible of course, but unlikely and suitable for most industry needs (e.g. aggregate tracking) 
    // 
    if (_openUDID==nil) { 
     CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); 
     CFStringRef cfstring = CFUUIDCreateString(kCFAllocatorDefault, uuid); 
     const char *cStr = CFStringGetCStringPtr(cfstring,CFStringGetFastestEncoding(cfstring)); 
     unsigned char result[16]; 
     CC_MD5(cStr, strlen(cStr), result); 
     CFRelease(uuid); 

     _openUDID = [NSString stringWithFormat: 
       @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x", 
       result[0], result[1], result[2], result[3], 
       result[4], result[5], result[6], result[7], 
       result[8], result[9], result[10], result[11], 
       result[12], result[13], result[14], result[15], 
        (NSUInteger)(arc4random() % NSUIntegerMax)]; 
    } 

    // Call to other developers in the Open Source community: 
    // 
    // feel free to suggest better or alternative "UDID" generation code above. 
    // NOTE that the goal is NOT to find a better hash method, but rather, find a decentralized (i.e. not web-based) 
    // 160 bits/20 bytes random string generator with the fewest possible collisions. 
    // 

    return _openUDID; 
} 

// Main public method that returns the OpenUDID 
// This method will generate and store the OpenUDID if it doesn't exist, typically the first time it is called 
// It will return the null udid (forty zeros) if the user has somehow opted this app out (this is subject to 3rd party implementation) 
// Otherwise, it will register the current app and return the OpenUDID 
// 
+ (NSString*) value { 
    return [Countly_OpenUDID valueWithError:nil]; 
} 

+ (NSString*) valueWithError:(NSError **)error { 

    if (kOpenUDIDSessionCache!=nil) { 
     if (error!=nil) 
      *error = [NSError errorWithDomain:kOpenUDIDDomain 
             code:kOpenUDIDErrorNone 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"OpenUDID in cache from first call",@"description", nil]]; 
     return kOpenUDIDSessionCache; 
    } 

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 

    // The AppUID will uniquely identify this app within the pastebins 
    // 
    NSString * appUID = (NSString *) [defaults objectForKey:kOpenUDIDAppUIDKey]; 
    if(appUID == nil) 
    { 
     // generate a new uuid and store it in user defaults 
     CFUUIDRef uuid = CFUUIDCreate(NULL); 
     appUID = (NSString *) CFUUIDCreateString(NULL, uuid); 
     CFRelease(uuid); 
    } 

    NSString* openUDID = nil; 
    NSString* myRedundancySlotPBid = nil; 
    NSDate* optedOutDate = nil; 
    BOOL optedOut = NO; 
    BOOL saveLocalDictToDefaults = NO; 
    BOOL isCompromised = NO; 

    // Do we have a local copy of the OpenUDID dictionary? 
    // This local copy contains a copy of the openUDID, myRedundancySlotPBid (and unused in this block, the local bundleid, and the timestamp) 
    // 
    id localDict = [defaults objectForKey:kOpenUDIDKey]; 
    if ([localDict isKindOfClass:[NSDictionary class]]) { 
     localDict = [NSMutableDictionary dictionaryWithDictionary:localDict]; // we might need to set/overwrite the redundancy slot 
     openUDID = [localDict objectForKey:kOpenUDIDKey]; 
     myRedundancySlotPBid = [localDict objectForKey:kOpenUDIDSlotKey]; 
     optedOutDate = [localDict objectForKey:kOpenUDIDOOTSKey]; 
     optedOut = optedOutDate!=nil; 
     OpenUDIDLog(@"localDict = %@",localDict); 
    } 

    // Here we go through a sequence of slots, each of which being a UIPasteboard created by each participating app 
    // The idea behind this is to both multiple and redundant representations of OpenUDIDs, as well as serve as placeholder for potential opt-out 
    // 
    NSString* availableSlotPBid = nil; 
    NSMutableDictionary* frequencyDict = [NSMutableDictionary dictionaryWithCapacity:kOpenUDIDRedundancySlots]; 
    for (int n=0; n<kOpenUDIDRedundancySlots; n++) { 
     NSString* slotPBid = [NSString stringWithFormat:@"%@%d",kOpenUDIDSlotPBPrefix,n]; 
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 
     UIPasteboard* slotPB = [UIPasteboard pasteboardWithName:slotPBid create:NO]; 
#else 
     NSPasteboard* slotPB = [NSPasteboard pasteboardWithName:slotPBid]; 
#endif 
     OpenUDIDLog(@"SlotPB name = %@",slotPBid); 
     if (slotPB==nil) { 
      // assign availableSlotPBid to be the first one available 
      if (availableSlotPBid==nil) availableSlotPBid = slotPBid; 
     } else { 
      NSDictionary* dict = [Countly_OpenUDID _getDictFromPasteboard:slotPB]; 
      NSString* oudid = [dict objectForKey:kOpenUDIDKey]; 
      OpenUDIDLog(@"SlotPB dict = %@",dict); 
      if (oudid==nil) { 
       // availableSlotPBid could inside a non null slot where no oudid can be found 
       if (availableSlotPBid==nil) availableSlotPBid = slotPBid; 
      } else { 
       // increment the frequency of this oudid key 
       int count = [[frequencyDict valueForKey:oudid] intValue]; 
       [frequencyDict setObject:[NSNumber numberWithInt:++count] forKey:oudid]; 
      } 
      // if we have a match with the app unique id, 
      // then let's look if the external UIPasteboard representation marks this app as OptedOut 
      NSString* gid = [dict objectForKey:kOpenUDIDAppUIDKey]; 
      if (gid!=nil && [gid isEqualToString:appUID]) { 
       myRedundancySlotPBid = slotPBid; 
       // the local dictionary is prime on the opt-out subject, so ignore if already opted-out locally 
       if (optedOut) { 
        optedOutDate = [dict objectForKey:kOpenUDIDOOTSKey]; 
        optedOut = optedOutDate!=nil; 
       } 
      } 
     } 
    } 

    // sort the Frequency dict with highest occurence count of the same OpenUDID (redundancy, failsafe) 
    // highest is last in the list 
    // 
    NSArray* arrayOfUDIDs = [frequencyDict keysSortedByValueUsingSelector:@selector(compare:)]; 
    NSString* mostReliableOpenUDID = (arrayOfUDIDs!=nil && [arrayOfUDIDs count]>0)? [arrayOfUDIDs lastObject] : nil; 
    OpenUDIDLog(@"Freq Dict = %@\nMost reliable %@",frequencyDict,mostReliableOpenUDID); 

    // if openUDID was not retrieved from the local preferences, then let's try to get it from the frequency dictionary above 
    // 
    if (openUDID==nil) {   
     if (mostReliableOpenUDID==nil) { 
      // this is the case where this app instance is likely to be the first one to use OpenUDID on this device 
      // we create the OpenUDID, legacy or semi-random (i.e. most certainly unique) 
      // 
      openUDID = [Countly_OpenUDID _generateFreshOpenUDID]; 
     } else { 
      // or we leverage the OpenUDID shared by other apps that have already gone through the process 
      // 
      openUDID = mostReliableOpenUDID; 
     } 
     // then we create a local representation 
     // 
     if (localDict==nil) { 
      localDict = [NSMutableDictionary dictionaryWithCapacity:4]; 
      [localDict setObject:openUDID forKey:kOpenUDIDKey]; 
      [localDict setObject:appUID forKey:kOpenUDIDAppUIDKey]; 
      [localDict setObject:[NSDate date] forKey:kOpenUDIDTSKey]; 
      if (optedOut) [localDict setObject:optedOutDate forKey:kOpenUDIDTSKey]; 
      saveLocalDictToDefaults = YES; 
     } 
    } 
    else { 
     // Sanity/tampering check 
     // 
     if (mostReliableOpenUDID!=nil && ![mostReliableOpenUDID isEqualToString:openUDID]) 
      isCompromised = YES; 
    } 

    // Here we store in the available PB slot, if applicable 
    // 
    OpenUDIDLog(@"Available Slot %@ Existing Slot %@",availableSlotPBid,myRedundancySlotPBid); 
    if (availableSlotPBid!=nil && (myRedundancySlotPBid==nil || [availableSlotPBid isEqualToString:myRedundancySlotPBid])) { 
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 
     UIPasteboard* slotPB = [UIPasteboard pasteboardWithName:availableSlotPBid create:YES]; 
     [slotPB setPersistent:YES]; 
#else 
     NSPasteboard* slotPB = [NSPasteboard pasteboardWithName:availableSlotPBid]; 
#endif 

     // save slotPBid to the defaults, and remember to save later 
     // 
     if (localDict) { 
      [localDict setObject:availableSlotPBid forKey:kOpenUDIDSlotKey]; 
      saveLocalDictToDefaults = YES; 
     } 

     // Save the local dictionary to the corresponding UIPasteboard slot 
     // 
     if (openUDID && localDict) 
      [Countly_OpenUDID _setDict:localDict forPasteboard:slotPB]; 
    } 

    // Save the dictionary locally if applicable 
    // 
    if (localDict && saveLocalDictToDefaults) 
     [defaults setObject:localDict forKey:kOpenUDIDKey]; 

    // If the UIPasteboard external representation marks this app as opted-out, then to respect privacy, we return the ZERO OpenUDID, a sequence of 40 zeros... 
    // This is a *new* case that developers have to deal with. Unlikely, statistically low, but still. 
    // To circumvent this and maintain good tracking (conversion ratios, etc.), developers are invited to calculate how many of their users have opted-out from the full set of users. 
    // This ratio will let them extrapolate convertion ratios more accurately. 
    // 
    if (optedOut) { 
     if (error!=nil) *error = [NSError errorWithDomain:kOpenUDIDDomain 
                code:kOpenUDIDErrorOptedOut 
               userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Application with unique id %@ is opted-out from OpenUDID as of %@",appUID,optedOutDate],@"description", nil]]; 

     kOpenUDIDSessionCache = [[NSString stringWithFormat:@"%040x",0] retain]; 
     return kOpenUDIDSessionCache; 
    } 

    // return the well earned openUDID! 
    // 
    if (error!=nil) { 
     if (isCompromised) 
      *error = [NSError errorWithDomain:kOpenUDIDDomain 
             code:kOpenUDIDErrorCompromised 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Found a discrepancy between stored OpenUDID (reliable) and redundant copies; one of the apps on the device is most likely corrupting the OpenUDID protocol",@"description", nil]]; 
     else 
      *error = [NSError errorWithDomain:kOpenUDIDDomain 
             code:kOpenUDIDErrorNone 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"OpenUDID succesfully retrieved",@"description", nil]]; 
    } 
    kOpenUDIDSessionCache = [openUDID retain]; 
    return kOpenUDIDSessionCache; 
} 


+ (void) setOptOut:(BOOL)optOutValue { 

    // init call 
    [Countly_OpenUDID value]; 

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 

    // load the dictionary from local cache or create one 
    id dict = [defaults objectForKey:kOpenUDIDKey]; 
    if ([dict isKindOfClass:[NSDictionary class]]) { 
     dict = [NSMutableDictionary dictionaryWithDictionary:dict]; 
    } else { 
     dict = [NSMutableDictionary dictionaryWithCapacity:2]; 
    } 

    // set the opt-out date or remove key, according to parameter 
    if (optOutValue) 
     [dict setObject:[NSDate date] forKey:kOpenUDIDOOTSKey]; 
    else 
     [dict removeObjectForKey:kOpenUDIDOOTSKey]; 

    // store the dictionary locally 
    [defaults setObject:dict forKey:kOpenUDIDKey]; 

    OpenUDIDLog(@"Local dict after opt-out = %@",dict); 

    // reset memory cache 
    kOpenUDIDSessionCache = nil; 

} 

@end 
+0

我得到的最長答案。謝謝。 –

+0

我得到的最長答案。謝謝。但我無法區分「登錄」按鈕和「同步」按鈕。 www.parse.com會將用戶會話保存在緩存中?如果服務器重啓?一切都輸了? –

+0

實際上解析它的相當不錯,會話直接在設備緩存中管理(實際上你必須手動註銷會話或解析會爲你做它,如果用戶刪除它)我現在它沒有任何差異在同步或日誌但如果你使用https://github.com/itsniper/FTASync,你甚至可以在設備之間同步這個帳戶,而不需要任何遠程對象處理,它的所有管理都乾淨並上傳每個對象來解析或更新它,許多關係都是爲你管理的 –

相關問題