Обычная аутентификация в Swift 3 не работает
Я борюсь с базовой аутентификацией в Swift.
У меня есть серверная служба Rest поверх SSL и с базовой аутентификацией. Мой клиентский код target-c работает хорошо, но соответствующий Swift-код не работает, потому что аутентификация не удалась.
Это код Swift:
let sUrl = "HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"
let url: URL = URL(string: sUrl)!
let request: URLRequest = URLRequest(url: url);
let session: URLSession = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue())
let task: URLSessionDataTask = session.dataTask(with: request) { (data, response, inError) in {
...
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
let details = [NSLocalizedDescriptionKey: "HTTP Error"]
let error = NSError(domain:"WS", code:httpResponse.statusCode, userInfo:details)
completionHandler(nil, error);
return
}
...
}
task.resume()
Метод делегата очень похож на соответствующий метод в Objective-c:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.previousFailureCount == 0 else {
challenge.sender?.cancel(challenge)
// Inform the user that the user name and password are incorrect
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let proposedCredential = URLCredential(user: user!, password: password!, persistence: .none)
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, proposedCredential)
}
HttpResponse.statusCode всегда 401.
Метод делегата вызывается только один раз, вместо этого соответствующий метод в Objective-c вызывается два раза.
Где я не прав?
ОБНОВЛЕНИЕ Соответствующий код Objective-c:
NSString *sUrl = [NSString stringWithFormat:@"HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"];
NSURL *url = [NSURL URLWithString:sUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *inError) {
if (inError != nil) {
completionHandler(0, inError);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode != 200) {
NSDictionary *details = @{NSLocalizedDescriptionKey:@"HTTP Error"};
NSError *error = [NSError errorWithDomain:@"WS" code:httpResponse.statusCode userInfo:details];
completionHandler(0, error);
return;
}
NSError *jsonError;
NSDictionary *valueAsDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
if (jsonError != nil) {
completionHandler(0, jsonError);
return;
}
if (![valueAsDictionary[@"ret"] boolValue]) {
NSInteger code = [valueAsDictionary[@"code"] integerValue];
NSDictionary *details = @{NSLocalizedDescriptionKey:(valueAsDictionary[@"message"]!=nil) ? valueAsDictionary[@"message"] : @""};
NSError *error = [NSError errorWithDomain:@"WS" code:code userInfo:details];
completionHandler(0, error);
return;
}
completionHandler(valueAsDictionary[@"value"], nil);
}];
[task resume];
Это функция делегата:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_user password:_password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
3 ответа
В конце концов мне удалось заставить его работать в Swift, даже если я не знаю, потому что раньше он не работал. Очевидно, что пользователь и пароль должны быть явно добавлены в заголовки HTTP.
let sUrl = "HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"
let url: URL = URL(string: sUrl)!
let request: URLRequest = URLRequest(url: url);
// Changes from here ...
let config = URLSessionConfiguration.default
let userPasswordData = "\(user!):\(password!)".data(using: .utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString(options: Data.Base64EncodingOptions.init(rawValue: 0))
let authString = "Basic \(base64EncodedCredential)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session: URLSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
// ... to here
let task: URLSessionDataTask = session.dataTask(with: request) { (data, response, inError) in {
...
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
let details = [NSLocalizedDescriptionKey: "HTTP Error"]
let error = NSError(domain:"WS", code:httpResponse.statusCode, userInfo:details)
completionHandler(nil, error);
return
}
...
}
task.resume()
Этот код работает для меня в Swift 3.0.1:
let login = "username"
let password = "password"
let sUrl = NSURL(string: (urlString as NSString) as String)
let request: URLRequest = URLRequest(url: sUrl as! URL);
let config = URLSessionConfiguration.default
let userPasswordData = "\(login):\(password)".data(using: .utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString(options: Data.Base64EncodingOptions.init(rawValue: 0))
let authString = "Basic \(base64EncodedCredential)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session: URLSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
print("response \(data)")
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
print(error?.localizedDescription as Any)
print("Handle Error")
}
else{
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
print("Synchronous\(jsonResult)")
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
task.resume()
}
По вашему вопросу это ваш запрос (строка).
let request: URLRequest = URLRequest (url: url);
Здесь вы не задали никаких параметров заголовка для своего экземпляра запроса. Пожалуйста, сравните заголовок запроса и параметры тела с вашим целевым клиентом C.
Параметры заголовка могут включать в себя - тип содержимого, а также другие полезные конфиденциальные параметры, такие как ключи API.
Проверьте ваш целевой клиентский запрос C и задайте те же параметры здесь, в вашем быстром коде