NSData不接受有效的base64编码字符串

Tom*_*usX 21 base64 json nsdata ios jwt

我正在iOS(7)客户端实现JSON Web Token身份验证.它工作得很好.我的应用程序接收令牌,并可以使用它们对我的服务器进行经过身份验证的调用.

现在,我希望我的客户端代码检查令牌上的到期日期,以便它可以知道何时重新进行身份验证.检查JWT身份验证令牌的到期日期非常简单.授权令牌是3个base64编码的JSON blob,用'.'分隔.- 到期时间戳位于中间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;
}
Run Code Online (Sandbox Code Playgroud)

问题很简单.中间base64 blob,当被NSData -initWithBase64EncodedString解析时是nil- 而且这很糟糕.

我检查了base64 blob,它似乎是有效的.我的服务器暂时返回虚拟数据所以这是一个示例blob: eyJlbWFpbCI6ImZvb0BiYXIuYmF6IiwiYWNjb3VudElkIjoiMTIzNDUtNjc4OTAtYmFyLWJheiIsImV4cCI6MTM5MDkxNTAzNywiaWF0IjoxMzkwOTE0MTM3fQ

它解码为:

{"email":"foo@bar.baz","accountId":"12345-67890-bar-baz","exp":1390915037,"iat":1390914137}
Run Code Online (Sandbox Code Playgroud)

我在这里测试了它:http://www.base64decode.org

我已经在我的应用程序中成功使用了NSData的base64方法 - 我不认为我在做任何特别破坏的事情.但我全都耳朵!有任何想法吗?

Mar*_*n R 37

您的Base64字符串无效.它必须用=字符填充,长度是4的倍数.在你的情况下:"eyJlbWFp....MTM3fQ==".

使用此填充,initWithBase64EncodedString正确解码Base64字符串.

  • 是的,你是对的,initWithBase64EncodedString不接受unpadded base64.这不是一个错误,但它们可以提供作为选项的功能.同时,你可以像这样自己填充字符串:int padLenght =(4 - (base64.length%4))%4; NSString*paddedBase64 = [NSString stringWithFormat:@"%s%.*s",[base64 UTF8String],padLenght,"=="]; (5认同)
  • 填充Base64数据不是强制性的,请参阅RFC的第3.2节:http://www.faqs.org/rfcs/rfc4648.html (3认同)
  • @droussel:谢谢你的反馈.NSData类中的方法不接受Base64字符串,该字符串未填充到4的倍数.我无法判断这是否是Apple框架中的错误或意图. (3认同)

小智 17

尽管Martin的答案是正确的,但这是解决问题的快速而正确的方法(!):

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

  • 在某些情况下,此答案将创建填充“ ====“。第二行末尾缺少“%4”。 (2认同)