23

我正在 iOS (7) cient 端实现 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;
}

问题很简单。当由 NSData -initWithBase64EncodedString 解析时,中间的 base64 blob 是nil- 这很糟糕。

我检查了base64 blob,它似乎是有效的。我的服务器目前正在返回虚拟数据,所以这里有一个示例 blob: eyJlbWFpbCI6ImZvb0BiYXIuYmF6IiwiYWNjb3VudElkIjoiMTIzNDUtNjc4OTAtYmFyLWJheiIsImV4cCI6MTM5MDkxNTAzNywiaWF0IjoxMzkwOTE0MTM3fQ

它解码为:

{"email":"foo@bar.baz","accountId":"12345-67890-bar-baz","exp":1390915037,"iat":1390914137}

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

我在我的应用程序的其他地方成功地使用了 NSData 的 base64 方法 - 我认为我在这里没有做任何特别糟糕的事情。但我全是耳朵!有任何想法吗?

4

5 回答 5

41

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

使用此填充,initWithBase64EncodedString可以正确解码 Base64 字符串。

于 2014-01-28T13:50:48.033 回答
20

尽管马丁的回答是正确的,但这里有一个快速且正确(!)的方法来解决这个问题:

NSString *base64String = @"<the token>";
NSUInteger paddedLength = base64String.length + (4 - (base64String.length % 4));
NSString* correctBase64String = [base64String stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];
于 2016-02-04T17:51:03.203 回答
4

这是一个适当地填充 Base-64 字符串并在 iOS 4+ 中工作的解决方案:

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
于 2015-07-15T22:18:21.367 回答
2

保罗答案的 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
}
于 2016-11-07T10:57:01.490 回答
0

我遇到了同样的问题,但通过==在字符串末尾添加来解决它

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)")
}

这肯定会奏效。

于 2016-02-29T12:40:14.150 回答