一,Alamofire的說明與配置
(1)Alamofire 的前身是 AFNetworking。AFNetworking 是 iOS 和 OS X 上很受歡迎的第三方HTTP網絡基礎庫。
(2)其實 AFNetwork 的前綴 AF 便是 Alamofire 的縮寫。
(3)Swift發布后,AFNetworking的作者又用Swift語言寫了個相同功能的庫,這便是 Alamofire。
(4)Alamofire 本質是基於`NSURLSession`,並做了封裝。使用 Alamofire 可以讓我們網絡請求相關代碼(如獲取數據,提交數據,上傳文件,下載文件等)更加簡潔易用。
(2)其實 AFNetwork 的前綴 AF 便是 Alamofire 的縮寫。
(3)Swift發布后,AFNetworking的作者又用Swift語言寫了個相同功能的庫,這便是 Alamofire。
(4)Alamofire 本質是基於`NSURLSession`,並做了封裝。使用 Alamofire 可以讓我們網絡請求相關代碼(如獲取數據,提交數據,上傳文件,下載文件等)更加簡潔易用。
關於Cookie:
Alamofire是基於NSURLRequest封裝的,所以Cookie會自動保存,就和瀏覽器請求是一個效果。而且網站Set_cookie多久, 本地的Cookie就多久,每次請求的時候都會自動帶上cookie,直到過期。(所以像登陸session這些的都不用我們手動去處理)
Alamofire是基於NSURLRequest封裝的,所以Cookie會自動保存,就和瀏覽器請求是一個效果。而且網站Set_cookie多久, 本地的Cookie就多久,每次請求的時候都會自動帶上cookie,直到過期。(所以像登陸session這些的都不用我們手動去處理)
2,Alamofire的功能特性:
(1)鏈式的請求/響應方法
(2)URL / JSON / plist參數編碼
(3)上傳類型支持:文件(File )、數據(Data )、流(Stream)以及MultipartFormData
(4)支持文件下載,下載支持斷點續傳
(5)支持使用NSURLCredential進行身份驗證
(6)HTTP響應驗證
(7)TLS Certificate and Public Key Pinning
(8)Progress Closure & NSProgress
3,Alamofire的安裝與配置
(1)從 GitHub 上下載最新的代碼: https://github.com/Alamofire/Alamofire
(2)將下載下來的源碼包中 Alamofire.xcodeproj 拖拽至你的工程中
(3)工程 -> General -> Embedded Binaries項,把iOS版的framework添加進來: Alamofire.framework
(4)最后,在需要使用 Alamofire 的地方 import 進來就可以了
1
|
import
Alamofire
|
二,使用Alamofire進行數據請求
1,以GET請求為例
(1)不帶參數,不帶結果處理
1
|
|
(2)帶參數,不帶結果處理
1
|
|
(3)帶參數,也帶結果處理(這里以返回結果為json格式的為例)
1
2
3
4
5
6
7
8
9
10
11
|
.responseJSON { response
in
print
(response.request)
// original URL request
print
(response.response)
// URL response
print
(response.data)
// server data
print
(response.result)
// result of response serialization
if
let
JSON
= response.result.value {
print
(
"JSON: \(JSON)"
)
//具體如何解析json內容可看下方“響應處理”部分
}
}
|
2,響應處理(Response Handling)
(1)除了上面樣例使用的responseJSON(處理json類型的返回結果)外,Alamofire還提供了許多其他類型的響應處理方法:
response()
responseData()
responseString(encoding: NSStringEncoding)
responseJSON(options: NSJSONReadingOptions)
responsePropertyList(options: NSPropertyListReadOptions)
responseData()
responseString(encoding: NSStringEncoding)
responseJSON(options: NSJSONReadingOptions)
responsePropertyList(options: NSPropertyListReadOptions)
(2)Response Handler
1
2
3
4
5
6
7
|
.response { request, response, data, error
in
print
(request)
print
(response)
print
(data)
print
(error)
}
|
1
2
3
4
5
6
|
.responseData { response
in
print
(response.request)
print
(response.response)
print
(response.result)
}
|
1
2
3
4
5
|
.responseString { response
in
print
(
"Success: \(response.result.isSuccess)"
)
print
(
"Response String: \(response.result.value)"
)
}
|
使用responseJSON 方法的話,JSON數據會被自動轉化為 NSDictionary或NSArray。假設我們返回的json數據格式如下:
使用responseJSON自動解析son數據:
(6)同樣也支持鏈式的返回結果處理
3,請求類型(HTTP Methods)
除了上面使用的 .Get 類型。Alamofire還定義了許多其他的HTTP 方法(HTTP Medthods)可以使用。
比如要使用 POST 請求,把 Alamofire.request 第一個參數做修改即可:
4,請求參數(Parameters)
(1)使用GET類型請求的時候,參數會自動拼接在url后面
(2)使用POST類型請求的時候,參數是放在在HTTP body里傳遞,url上看不到
5,參數編碼方式(Parameter Encoding)
除了默認的方式外,Alamofire還支持URL、URLEncodedInURL、JSON、Property List以及自定義格式方式編碼參數。
比如我們想要把一個字典類型的數據,使用json格式發起POST請求:
服務端php頁面可以這么取得發送過來的JSON數據:
6,支持自定義Http頭信息(HTTP Headers)
三,判斷數據請求是否成功,並做相應的處理
在請求響應對象之前調用的 .validate() 函數是另一個易用的 Alamofire 特性。
將其與請求和響應鏈接,以確認響應的狀態碼在默認可接受的范圍(200到299)內。如果認證失敗,響應處理方法將出現一個相關錯誤,我們可以根據不同在完成處理方法中處理這個錯誤。
比如下面的樣例,成功時會打印成功信息,失敗時輸出具體錯誤信息。
四,打印調試(print和debugPrint)
不管是 request對象還是 response對象都是支持打印輸出的。根據不同的調試需求,我們可以自行選擇使用 print 還是 debugPrint。
1,打印request對象
2,打印response對象
[
{
"name": "hangge",
"phones": [
{
"name": "公司",
"number": "123456"
},
{
"name": "家庭",
"number": "001"
}
]
},
{
"name": "big boss",
"phones": [
{
"name": "公司",
"number": "111111"
}
]
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
.responseJSON { response
in
switch
response.result {
case
.
Success
:
//把得到的JSON數據轉為數組
if
let
items = response.result.value
as
?
NSArray
{
//遍歷數組得到每一個字典模型
for
dict
in
items{
print
(dict)
}
}
case
.
Failure
(
let
error):
print
(error)
}
}
|
1
2
3
4
5
6
7
|
.responseString { response
in
print
(
"Response String: \(response.result.value)"
)
}
.responseJSON { response
in
print
(
"Response JSON: \(response.result.value)"
)
}
|
除了上面使用的 .Get 類型。Alamofire還定義了許多其他的HTTP 方法(HTTP Medthods)可以使用。
1
2
3
|
public
enum
Method
:
String
{
case
OPTIONS
,
GET
,
HEAD
,
POST
,
PUT
,
PATCH
,
DELETE
,
TRACE
,
CONNECT
}
|
1
|
|
4,請求參數(Parameters)
(1)使用GET類型請求的時候,參數會自動拼接在url后面
1
2
|
|
1
2
3
4
5
6
7
8
9
10
11
12
|
let
parameters = [
"foo"
:
"bar"
,
"baz"
: [
"a"
, 1],
"qux"
: [
"x"
: 1,
"y"
: 2,
"z"
: 3
]
]
// HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
|
5,參數編碼方式(Parameter Encoding)
除了默認的方式外,Alamofire還支持URL、URLEncodedInURL、JSON、Property List以及自定義格式方式編碼參數。
1
2
3
4
5
6
7
8
9
10
|
enum
ParameterEncoding
{
case
URL
case
URLEncodedInURL
case
JSON
case
PropertyList
(format:
NSPropertyListFormat
, options:
NSPropertyListWriteOptions
)
case
Custom
((
URLRequestConvertible
, [
String
:
AnyObject
]?) -> (
NSMutableURLRequest
,
NSError
?))
func
encode(request:
NSURLRequest
, parameters: [
String
:
AnyObject
]?) -> (
NSURLRequest
,
NSError
?)
{ ... }
}
|
1
2
3
4
5
6
7
8
9
|
let
parameters = [
"foo"
: [1,2,3],
"bar"
: [
"baz"
:
"qux"
]
]
// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
|
1
2
3
4
5
6
7
8
|
<?
$foo
=
$postdata
[
"foo"
];
foreach
(
$foo
as
$item
){
echo
$item
.
"|"
;
}
//輸出:1|2|3|
|
6,支持自定義Http頭信息(HTTP Headers)
1
2
3
4
5
6
7
8
9
|
let
headers = [
"Authorization"
:
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
,
"Content-Type"
:
"application/x-www-form-urlencoded"
]
.responseJSON { response
in
debugPrint(response)
}
|
三,判斷數據請求是否成功,並做相應的處理
在請求響應對象之前調用的 .validate() 函數是另一個易用的 Alamofire 特性。
將其與請求和響應鏈接,以確認響應的狀態碼在默認可接受的范圍(200到299)內。如果認證失敗,響應處理方法將出現一個相關錯誤,我們可以根據不同在完成處理方法中處理這個錯誤。
比如下面的樣例,成功時會打印成功信息,失敗時輸出具體錯誤信息。
1
2
3
4
5
6
7
8
9
10
|
.validate()
.responseJSON { response
in
switch
response.result {
case
.
Success
:
print
(
"數據獲取成功!"
)
case
.
Failure
(
let
error):
print
(error)
}
}
|
四,打印調試(print和debugPrint)
不管是 request對象還是 response對象都是支持打印輸出的。根據不同的調試需求,我們可以自行選擇使用 print 還是 debugPrint。
1,打印request對象
1
2
3
4
5
6
|
print
(request)
/********** 下面是控制台輸出 ***************
******************************************/
|
1
2
3
4
5
6
7
8
9
10
|
debugPrint(request)
/********** 下面是控制台輸出 ***************
$ curl -i \
-H "User-Agent: hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))" \
-H "Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
-H "Accept-Language: zh-Hans-CN;q=1.0,en-CN;q=0.9" \
******************************************/
|
2,打印response對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
.responseString { response
in
debugPrint(response)
}
/********** 下面是控制台輸出 ***************
SUCCESS: {
"args": {},
"headers": {
"Accept": "*/
*",
"Accept-Encoding"
:
"gzip;q=1.0,compress;q=0.5"
,
"Accept-Language"
:
"zh-Hans-CN;q=1.0,en-CN;q=0.9"
,
"Host"
:
"httpbin.org"
,
"User-Agent"
:
"hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))"
},
"origin"
:
"180.109.163.139"
,
}
******************************************/
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
.responseString { response
in
print
(response)
}
/********** 下面是控制台輸出 ***************
[Request]: <NSMutableURLRequest: 0x7889c780> { URL: https://httpbin.org/get }
[Response]: <NSHTTPURLResponse: 0x7896f500> { URL: https://httpbin.org/get } { status code: 200, headers {
"Access-Control-Allow-Origin" = "*";
"Content-Length" = 354;
"Content-Type" = "application/json";
Date = "Tue, 08 Dec 2015 01:57:45 GMT";
Server = nginx;
"access-control-allow-credentials" = true;
} }
[Data]: 354 bytes
[Result]: SUCCESS: {
"args": {},
"headers": {
"Accept": "*/
*",
"Accept-Encoding"
:
"gzip;q=1.0,compress;q=0.5"
,
"Accept-Language"
:
"zh-Hans-CN;q=1.0,en-CN;q=0.9"
,
"Host"
:
"httpbin.org"
,
"User-Agent"
:
"hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))"
},
"origin"
:
"180.109.163.139"
,
}
******************************************/
|
六,使用Alamofire進行文件上傳
File
Data
Stream
MultipartFormData
Data
Stream
MultipartFormData
2,使用文件流的形式上傳文件
1
2
3
|
let
fileURL =
NSBundle
.mainBundle().
URLForResource
(
"hangge"
, withExtension:
"zip"
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<?php
/** php 接收流文件
* @param String $file 接收后保存的文件名
* @return boolean
*/
function
receiveStreamFile(
$receiveFile
){
$streamData
= isset(
$GLOBALS
[
'HTTP_RAW_POST_DATA'
])?
$GLOBALS
[
'HTTP_RAW_POST_DATA'
] :
''
;
if
(
empty
(
$streamData
)){
}
if
(
$streamData
!=
''
){
$ret
=
file_put_contents
(
$receiveFile
,
$streamData
, true);
}
else
{
$ret
= false;
}
return
$ret
;
}
//定義服務器存儲路徑和文件名
$receiveFile
=
$_SERVER
[
"DOCUMENT_ROOT"
].
"/uploadFiles/hangge.zip"
;
$ret
= receiveStreamFile(
$receiveFile
);
echo
json_encode(
array
(
'success'
=>(bool)
$ret
));
?>
|
3,上傳時附帶上傳進度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
let
fileURL =
NSBundle
.mainBundle().
URLForResource
(
"hangge"
, withExtension:
"zip"
)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite
in
print
(totalBytesWritten)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print
(
"Total bytes written on main queue: \(totalBytesWritten)"
)
}
}
.responseJSON { response
in
debugPrint(response)
}
|
4,上傳MultipartFormData類型的文件數據(類似於網頁上Form表單里的文件提交)
(1)上傳兩個文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
let
fileURL1 =
NSBundle
.mainBundle().
URLForResource
(
"hangge"
, withExtension:
"png"
)
let
fileURL2 =
NSBundle
.mainBundle().
URLForResource
(
"hangge"
, withExtension:
"zip"
)
Alamofire
.upload(
.
POST
,
multipartFormData: { multipartFormData
in
multipartFormData.appendBodyPart(fileURL: fileURL1!, name:
"file1"
)
multipartFormData.appendBodyPart(fileURL: fileURL2!, name:
"file2"
)
},
encodingCompletion: { encodingResult
in
switch
encodingResult {
case
.
Success
(
let
upload, _, _):
upload.responseJSON { response
in
debugPrint(response)
}
case
.
Failure
(
let
encodingError):
print
(encodingError)
}
}
)
|
1
2
3
4
5
6
7
|
<?
move_uploaded_file(
$_FILES
[
"file1"
][
"tmp_name"
],
$_SERVER
[
"DOCUMENT_ROOT"
].
"/uploadFiles/"
.
$_FILES
[
"file1"
][
"name"
]);
move_uploaded_file(
$_FILES
[
"file2"
][
"tmp_name"
],
$_SERVER
[
"DOCUMENT_ROOT"
].
"/uploadFiles/"
.
$_FILES
[
"file2"
][
"name"
]);
?>
|
(2)文本參數與文件一起提交(文件除了可以使用fileURL,還可以上傳NSData類型的文件數據)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
//字符串
let
strData =
"hangge.com"
.dataUsingEncoding(
NSUTF8StringEncoding
)
//數字
let
intData =
String
(10).dataUsingEncoding(
NSUTF8StringEncoding
)
//文件1
let
path =
NSBundle
.mainBundle().pathForResource(
"hangge"
, ofType:
"png"
)!
let
file1Data =
NSData
(contentsOfFile: path)
//文件2
let
file2URL =
NSBundle
.mainBundle().
URLForResource
(
"hangge"
, withExtension:
"zip"
)
Alamofire
.upload(
.
POST
,
multipartFormData: { multipartFormData
in
multipartFormData.appendBodyPart(data: strData!, name:
"value1"
)
multipartFormData.appendBodyPart(data: intData!, name:
"value2"
)
multipartFormData.appendBodyPart(data: file1Data!, name:
"file1"
,
fileName:
"h.png"
, mimeType:
"image/png"
)
multipartFormData.appendBodyPart(fileURL: file2URL!, name:
"file2"
)
},
encodingCompletion: { encodingResult
in
switch
encodingResult {
case
.
Success
(
let
upload, _, _):
upload.responseString { response
in
print
(response)
}
case
.
Failure
(
let
encodingError):
print
(encodingError)
}
}
)
|
1
2
3
4
5
6
7
8
9
10
|
<?
$value1
=
$_POST
[
"value1"
];
$value2
=
$_POST
[
"value2"
];
move_uploaded_file(
$_FILES
[
"file1"
][
"tmp_name"
],
$_SERVER
[
"DOCUMENT_ROOT"
].
"/uploadFiles/"
.
$_FILES
[
"file1"
][
"name"
]);
move_uploaded_file(
$_FILES
[
"file2"
][
"tmp_name"
],
$_SERVER
[
"DOCUMENT_ROOT"
].
"/uploadFiles/"
.
$_FILES
[
"file2"
][
"name"
]);
?>
|
七,使用Alamofire進行文件下載
下面代碼將logo圖片下載下來保存到用戶文檔目錄下(Documnets目錄),文件名不變。
1
2
3
4
5
6
7
8
9
|
temporaryURL, response
in
let
fileManager =
NSFileManager
.defaultManager()
let
directoryURL = fileManager.
URLsForDirectory
(.
DocumentDirectory
,
inDomains: .
UserDomainMask
)[0]
let
pathComponent = response.suggestedFilename
return
directoryURL.
URLByAppendingPathComponent
(pathComponent!)
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
temporaryURL, response
in
let
fileManager =
NSFileManager
.defaultManager()
let
directoryURL = fileManager.
URLsForDirectory
(.
DocumentDirectory
,
inDomains: .
UserDomainMask
)[0]
let
folder = directoryURL.
URLByAppendingPathComponent
(
"file1"
, isDirectory:
true
)
//判斷文件夾是否存在,不存在則創建
let
exist = fileManager.fileExistsAtPath(folder.path!)
if
!exist {
try! fileManager.createDirectoryAtURL(folder, withIntermediateDirectories:
true
,
attributes:
nil
)
}
return
folder.
URLByAppendingPathComponent
(
"myLogo.png"
)
}
|
2,使用默認提供的下載路徑
Alamofire內置的許多常用的下載路徑方便我們使用,簡化代碼。比如,下載到用戶文檔目錄下可以改成:
1
2
3
4
5
|
let
destination =
Alamofire
.
Request
.suggestedDownloadDestination(
directory: .
DocumentDirectory
, domain: .
UserDomainMask
)
destination: destination)
|
3,下載進度
下面代碼在文件下載過程中會不斷地打印下載進度,同時下載完成后也會打印完成信息。
1
2
3
4
5
6
7
8
9
10
11
|
let
destination =
Alamofire
.
Request
.suggestedDownloadDestination(
directory: .
DocumentDirectory
, domain: .
UserDomainMask
)
.progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead)
in
let
percent = totalBytesRead*100/totalBytesExpectedToRead
print
(
"已下載:\(totalBytesRead) 當前進度:\(percent)%"
)
}
.response { (request, response, _, error)
in
print
(response)
}
|
4,斷點續傳(Resume Data)
當下載過程中被意外停止時,可以在響應方法中把已下載的部分保存起來,下次再從斷點繼續下載。
下面通過樣例演示如何斷點續傳:
(1)程序啟動后自動開始下載文件
(2)點擊“停止下載”,終止下載並把已下載的數據保存起來,進度條停止走動。
(3)點擊“繼續下載”,從上次終止的地方繼續下載,進度條繼續走動。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import
UIKit
import
Alamofire
class
ViewController
:
UIViewController
{
//停止下載按鈕
@IBOutlet
weak
var
stopBtn:
UIButton
!
//繼續下載按鈕
@IBOutlet
weak
var
continueBtn:
UIButton
!
//下載進度條
@IBOutlet
weak
var
progress:
UIProgressView
!
//下載文件的保存路徑
let
destination =
Alamofire
.
Request
.suggestedDownloadDestination(
directory: .
DocumentDirectory
, domain: .
UserDomainMask
)
//用於停止下載時,保存已下載的部分
var
cancelledData:
NSData
?
//下載請求對象
var
downloadRequest:
Request
!
override
func
viewDidLoad() {
super
.viewDidLoad()
//頁面加載完畢就自動開始下載
self
.downloadRequest =
Alamofire
.download(.
GET
,
destination: destination)
self
.downloadRequest.progress(downloadProgress)
//下載進度
self
.downloadRequest.response(completionHandler: downloadResponse)
//下載停止響應
}
//下載過程中改變進度條
func
downloadProgress(bytesRead:
Int64
, totalBytesRead:
Int64
,
totalBytesExpectedToRead:
Int64
) {
let
percent =
Float
(totalBytesRead)/
Float
(totalBytesExpectedToRead)
//進度條更新
dispatch_async(dispatch_get_main_queue(), {
self
.progress.setProgress(percent,animated:
true
)
})
print
(
"當前進度:\(percent*100)%"
)
}
//下載停止響應(不管成功或者失敗)
func
downloadResponse(request:
NSURLRequest
?, response:
NSHTTPURLResponse
?,
data:
NSData
?, error:
NSError
?) {
if
let
error = error {
if
error.code ==
NSURLErrorCancelled
{
self
.cancelledData = data
//意外終止的話,把已下載的數據儲存起來
}
else
{
print
(
"Failed to download file: \(response) \(error)"
)
}
}
else
{
print
(
"Successfully downloaded file: \(response)"
)
}
}
//停止按鈕點擊
@IBAction
func
stopBtnClick(sender:
AnyObject
) {
self
.downloadRequest?.cancel()
self
.stopBtn.enabled =
false
self
.continueBtn.enabled =
true
}
//繼續按鈕點擊
@IBAction
func
continueBtnClick(sender:
AnyObject
) {
if
let
cancelledData =
self
.cancelledData {
self
.downloadRequest =
Alamofire
.download(resumeData: cancelledData,
destination: destination)
self
.downloadRequest.progress(downloadProgress)
//下載進度
self
.downloadRequest.response(completionHandler: downloadResponse)
//下載停止響應
self
.stopBtn.enabled =
true
self
.continueBtn.enabled =
false
}
}
override
func
didReceiveMemoryWarning() {
super
.didReceiveMemoryWarning()
}
}
|
八,使用Alamofire進行用戶認證
比如:路由器的配置頁面就常使用HTTP Basic認證。(瀏覽器輸入路由器ip地址,如192.168.1.1,這時就會彈出個用戶密碼輸入框進行權限驗證。)
(2)BASE64 的加密強度非常低。當然,HTTP基本認證系統也可以與SSL或者Kerberos結合,實現安全性能較高(相對)的認證系統。
使用瀏覽器訪問這個authenticate.php頁面,則會彈出對話框要求輸入用戶名和密碼:
如果輸入正確的用戶名(hangge)和密碼(123)則返回正常的數據,否則返回錯誤信息並需要繼續輸入:
6,客戶端代碼
從控制台打印的消息可以看出,認證通過,並成功獲取到數據:
1,Alamofire支持如下幾種認證(Authentication)
HTTP Basic
HTTP Digest
Kerberos
NTLM
本文講解使用 Alamofire 進行 HTTP Basic 驗證。
HTTP Digest
Kerberos
NTLM
2,HTTP Basic認證介紹
(1)HTTP Basic認證是允許HTTP服務器對WEB瀏覽器進行用戶身份證的方法。
(2)當一個客戶端向HTTP服務器進行數據請求時,客戶端會接收到HTTP服務器的身份認證要求,這時客戶端會提示用戶輸入用戶名及密碼,然后將用戶名及密碼以BASE64加密。並於每次請求數據時,將密文附加於請求頭(Request Header)中。
(3)HTTP服務器在每次收到請求包后,根據協議取得客戶端附加的用戶信息(BASE64加密的用戶名和密碼),解開請求包,對用戶名及密碼進行驗證, 如果用戶名及密碼正確,則根據客戶端請求,返回客戶端所需要的數據。否則,返回錯誤代碼或重新要求客戶端提供用戶名及密碼。
3,HTTP Basic認證的使用場景
HTTP基本認證只提供簡單的用戶驗證功能,優點是使用簡單,適合於對安全性要求不高的系統或設備中。
比如:路由器的配置頁面就常使用HTTP Basic認證。(瀏覽器輸入路由器ip地址,如192.168.1.1,這時就會彈出個用戶密碼輸入框進行權限驗證。)
4,HTTP Basic認證的缺點
(1)沒有靈活可靠的認證策略,如無法提供域(domain或realm)認證功能。
(2)BASE64 的加密強度非常低。當然,HTTP基本認證系統也可以與SSL或者Kerberos結合,實現安全性能較高(相對)的認證系統。
5,服務端代碼
為了測試Alamofire的認證功能,我們首先要在服務端創建個帶有認證的頁面用於測試。這里以PHP為例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<?php
//HTTP Basic認證
function
authenticate()
{
header(
'WWW-Authenticate: Basic realm=""'
);
header(
'HTTP/1.0 401 Unauthorized'
);
echo
"請輸入正確的用戶名和密碼"
;
exit
;
}
if
(!isset(
$_SERVER
[
'PHP_AUTH_USER'
]) ||
addslashes
(
$_SERVER
[
'PHP_AUTH_USER'
])!=
'hangge'
||
addslashes
(
$_SERVER
[
'PHP_AUTH_PW'
])!=
'123'
)
{
//認證失敗
authenticate();
}
else
{
//認證成功
echo
"歡迎您: {$_SERVER['PHP_AUTH_USER']}<br />"
;
echo
"當前時間:"
.
date
(
'h:i:s'
);
//authenticate(); //重新開始
}
?>
|
6,客戶端代碼
使用Alamofire進行認證:
1
2
3
4
5
6
7
8
9
|
let
user =
"hangge"
let
password =
"123"
.authenticate(user: user, password: password)
.responseString { response
in
// debugPrint(response)
print
(response.result.value)
}
|