web-dev-qa-db-ja.com

NSDataは有効なbase64エンコード文字列を受け入れません

IOS(7)のcient-sideでJSON WebToken認証を実装しています。それはうまく機能しています。私のアプリはトークンを受け取り、トークンを使用してサーバーに認証済みの呼び出しを行うことができます。

ここで、クライアント側のコードでトークンの有効期限を確認して、いつ再認証するかを認識できるようにします。 JWT認証トークンの有効期限の確認は簡単です。承認トークンは、「。」で区切られた3つのbase64エンコードJSONブロブです。 -有効期限のタイムスタンプは、中央のblobのextというフィールドにあります。 UNIXエポックから数秒です。

したがって、私のコードは次のようになります。

- (NSDate*) expirationDate
{
    if ( !_tokenAppearsValid ) return nil;

    if ( !_parsedExpirationDate )
    {
        //
        //  Token is three base64 encoded payloads separated by '.'
        //  The payload we want is the middle one, which is a JSON dict, with
        //  'exp' being the unix seconds timestamp of the expiration date
        //  Returning nil is appropriate if no 'exp' is findable
        //

        NSArray *components = [self.token componentsSeparatedByString:@"."];

        NSString *payload = components[1];

        NSData* payloadJsonData = [[NSData alloc]
            initWithBase64EncodedString:payload
            options:NSDataBase64DecodingIgnoreUnknownCharacters];

        NSError* jsonError = nil;
        NSDictionary* payloadJson = [NSJSONSerialization JSONObjectWithData:payloadJsonData options:0 error:&jsonError];
        if ( payloadJson )
        {
            if ( payloadJson[@"exp"] )
            {
                NSTimeInterval timestampSeconds = [payloadJson[@"exp"] doubleValue];
                _expirationDate = [NSDate dateWithTimeIntervalSince1970:timestampSeconds];
            }
        }

        _parsedExpirationDate = YES;
    }

    return _expirationDate;
}

問題は単純です。 NSData-initWithBase64EncodedStringで解析した場合の中央のbase64blobはnil-であり、これは問題です。

Base64 BLOBを確認しましたが、有効なようです。今のところサーバーがダミーデータを返しているので、blobの例を次に示します。eyJlbWFpbCI6ImZvb0BiYXIuYmF6IiwiYWNjb3VudElkIjoiMTIzNDUtNjc4OTAtYmFyLWJheiIsImV4cCI6MTM5MDkxNTAzNywiaWF0IjoxMzkwOTE0MTM3fQ

次のようにデコードします。

{"email":"[email protected]","accountId":"12345-67890-bar-baz","exp":1390915037,"iat":1390914137}

ここでテストしました: http://www.base64decode.org

私はアプリの他の場所でNSDataのbase64メソッドを使用して成功しましたが、ここで特に壊れていることは何もしていないと思います。しかし、私はすべての耳です!何か案は?

22
TomorrowPlusX

Base64文字列が無効です。 4の倍数の長さにするには、=文字を埋め込む必要があります。この場合:"eyJlbWFp....MTM3fQ=="

このパディングを使用すると、initWithBase64EncodedStringはBase64文字列を正しくデコードします。

38
Martin R

マーティンの答えは正しいですが、問題を解決するための迅速で正しい(!)方法は次のとおりです。

NSString *base64String = @"<the token>";
NSUInteger paddedLength = base64String.length + (4 - (base64String.length % 4));
NSString* correctBase64String = [base64String stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];
17
christopher

Base-64文字列を適切にパディングし、iOS4以降で機能するソリューションは次のとおりです。

NSData + Base64.h

@interface NSData (Base64)

/**
 Returns a data object initialized with the given Base-64 encoded string.
 @param base64String A Base-64 encoded NSString
 @returns A data object built by Base-64 decoding the provided string. Returns nil if the data object could not be decoded.
 */
- (instancetype) initWithBase64EncodedString:(NSString *)base64String;

/**
 Create a Base-64 encoded NSString from the receiver's contents
 @returns A Base-64 encoded NSString
 */
- (NSString *) base64EncodedString;

@end

NSData + Base64.m

@interface NSString (Base64)

- (NSString *) stringPaddedForBase64;

@end

@implementation NSString (Base64)

- (NSString *) stringPaddedForBase64 {
    NSUInteger paddedLength = self.length + (self.length % 3);
    return [self stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];
}

@end

@implementation NSData (Base64)

- (instancetype) initWithBase64EncodedString:(NSString *)base64String {
    return [self initWithBase64Encoding:[base64String stringPaddedForBase64]];
}

- (NSString *) base64EncodedString {
    return [self base64Encoding];
}

@end
4
phatmann

A Swiftバージョン ポールの答え

func paddedBase64EncodedString(encodedString: String) -> String
{
    let encodedStringLength = encodedString.characters.count
    let paddedLength = encodedStringLength + (4 - (encodedStringLength % 4))
    let paddedBase64String = encodedString.stringByPaddingToLength(paddedLength,
                                                                    withString: "=",
                                                                    startingAtIndex: 0)

    return paddedBase64String
}
2
Simo

同じ問題に直面しましたが、文字列の最後に==を追加することで解決しました

base64UserStr = NSString(format: "%@%@", base64UserStr,"==") as String
let decodedData = NSData(base64EncodedString: base64UserStr, options: NSDataBase64DecodingOptions.init(rawValue: 0))


if (decodedData != nil)
{
    let decodedString = NSString(data: decodedData!, encoding: NSUTF8StringEncoding)

    print("Base 64 decode string is \(decodedString)")
}

これは間違いなく機能します。

0
Anita