我正在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;
}
问题很简单。中间base64 blob,当由NSData -initWithBase64EncodedString解析时为nil
- 这很糟糕。
我检查了base64 blob,它似乎是有效的。我的服务器暂时返回虚拟数据所以这是一个示例blob:
eyJlbWFpbCI6ImZvb0BiYXIuYmF6IiwiYWNjb3VudElkIjoiMTIzNDUtNjc4OTAtYmFyLWJheiIsImV4cCI6MTM5MDkxNTAzNywiaWF0IjoxMzkwOTE0MTM3fQ
它解码为:
{"email":"foo@bar.baz","accountId":"12345-67890-bar-baz","exp":1390915037,"iat":1390914137}
我在这里测试了它:http://www.base64decode.org
我已经在我的应用程序中成功使用了NSData的base64方法 - 我不认为我在做什么特别破坏了。但我全都耳朵!有什么想法吗?
答案 0 :(得分:36)
您的Base64字符串无效。必须用=
个字符填充
长度是4的倍数。在您的情况下:"eyJlbWFp....MTM3fQ=="
。
使用此填充,initWithBase64EncodedString
正确解码Base64字符串。
答案 1 :(得分:17)
虽然马丁的答案是正确的,但这是解决问题的快速和正确的方法:
NSString *base64String = @"<the token>";
NSUInteger paddedLength = base64String.length + (4 - (base64String.length % 4));
NSString* correctBase64String = [base64String stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];
答案 2 :(得分: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
答案 3 :(得分:2)
Swift版本的Paul's answer
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
}
答案 4 :(得分: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)")
}
这肯定会奏效。