rest-assured支持多種認證授權方案,比如:OAuth、digest(摘要認證)、certificate(證書認證)、form(表單認證)以及preemptive(搶占式基礎認證)等。我們可以單獨為某一個請求設置認證授權:
1 given().auth().basic("username", "password"). ..
我們也可以為所有的請求定義一個認證授權:
1 RestAssured.authentication = basic("username", "password");
一、基礎認證
這里有兩種基礎認證方式:搶占式基礎認證(preemptive basic authentication)和受質詢式基礎認證(challenged basic authentication)。
1.搶占式基礎認證(preemptive basic authentication)
服務器某些情況下在給出未授權響應之前會發送一個基礎認證憑證,從而減少額外的連接開銷。這是非常典型的,我們大多數情況下都是使用這個,除非我們是在測試服務器的極限。比如說:
1 given().auth().preemptive().basic("username", "password").when().get("/secured/hello").then().statusCode(200);
2.受質詢式基礎認證(challenged basic authentication)
當我們使用受質詢式基礎認證時,除非服務端明確的索要認證憑證,否則rest-assured將不會提供認證憑證。這就意味着為了進行質詢,rest-assured將會額外的發送一個請求到服務端,然后接着會發送相同的請求,但此時會在header中設置認證憑證:
1 given().auth().basic("username", "password").when().get("/secured/hello").then().statusCode(200);
二、摘要認證(Digest Authentication)
目前只支持 受質詢式基礎認證(challenged basic authentication)的摘要認證:
1 given().auth().digest("username", "password").when().get("/secured"). ..
三、表單認證(Form Authentication)
表單認證在互聯網上是非常受歡迎的一種認證。最典型的例子就是用戶在web網頁上填寫證書(username and password 用戶名和密碼),然后點擊登錄按鈕發起請求。下面是一個非常簡單的HTML頁面,用來展示這種表單認證:
1 <html> 2 <head> 3 <title>Login</title> 4 </head> 5 6 <body> 7 <form action="j_spring_security_check" method="POST"> 8 <table> 9 <tr><td>User: </td><td><input type='text' name='j_username'></td></tr> 10 <tr><td>Password:</td><td><input type='password' name='j_password'></td></tr> 11 <tr><td colspan='2'><input name="submit" type="submit"/></td></tr> 12 </table> 13 </form> 14 </body> 15 </html>
假如,服務端期望用戶輸入用戶名( j_username )和密碼( j_password ),然后點擊submit按鈕去登錄,那么我們可以使用rest-assured來測試一下這樣的需要進行表單認證的服務:
1 given(). 2 auth().form("John", "Doe"). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
雖然這種做法可能不是最佳的。那么當我們在rest-assured中使用這樣的表單認證時究竟發生了什么呢?rest-assured在使用這種表單認證時需要發送一個額外的請求到服務端獲取登錄頁面,然后rest-assured會嘗試解析這個登錄頁面,從而獲得登錄和密碼兩個輸入框以及表單提交的路徑(form action url),請求可能會成功或者是失敗,這取決於網頁的復雜程度。這里有一種更好的方法,那就是在設置表單認證的時候直接給rest-assured提供這些參數信息。上面的例子我們還可以這樣做:
1 given(). 2 auth().form("John", "Doe", new FormAuthConfig("/j_spring_security_check", "j_username", "j_password")). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
使用上面這種方式rest-assured就不需要在額外發送請求和解析網頁了。如果我們想使用默認的Spring Security 屬性,這用到一個叫 springSecurity 的預定義 FormAuthConfig :
1 given(). 2 auth().form("John", "Doe", FormAuthConfig.springSecurity()). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
四、CSRF(跨站請求偽造,Cross-site request forgery的縮寫,也可以縮寫為:XSRF)
當今,服務端為了防止某些攻擊在響應體中提供 CSRF token值是非常常見的了。rest-assured支持自動解析並提供 CSRF token值給服務端,為了實現這個功能,rest-assured必須發送一個額外的請求來解析這個網站(或者是網站的部分內容)。
我們通過下面的方式可以啟用 rest-assured 對 CSRF的支持:
1 given(). 2 auth().form("John", "Doe", formAuthConfig().withAutoDetectionOfCsrf()). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
現在rest-assured將會自動嘗試檢車該網站是否包含了CSRF token。為了幫助rest-assured解析更加順利,我們可能需要提供一個CSRF域的名字(這里我們假設我們使用的是Spring Security默認值,這樣我們就可以使用預定義的 springSecurity 表單認證配置(FormAuthConfig)):
1 given(). 2 auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf")). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
這里我們告訴rest-assured去查找一個名為"_csrf" 的 CSRF域(這樣不但效率變高了,也更不易出錯)。
默認情況下,CSRF的值是作為請求參數發送的,但是我們也可以配置CSRF的值作為header發送,那么我們需要這樣做:
1 given(). 2 auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf").sendCsrfTokenAsHeader()). 3 when(). 4 get("/formAuth"); 5 then(). 6 statusCode(200);
五、OAuth授權
為了能夠使用OAuth 1 和 OAuth 2(關於查詢請求參數簽名的機制),我們需要添加 Scribe 到我們的 classpath 中(如果使用的是 2.1.0版本或者是更老版本的rest-assured,請參考老版的rest-assured指南)。在maven中我們可以通過下面的方式來添加依賴:
1 <dependency> 2 <groupId>com.github.scribejava</groupId> 3 <artifactId>scribejava-apis</artifactId> 4 <version>2.5.3</version> 5 <scope>test</scope> 6 </dependency>
1.OAuth 1 認證
OAuth 1 認證需要添加 scribe 到classpath中,使用 OAuth 1 認證我們可以這樣寫:
1 given().auth().oauth(..). ..
2.OAuth 2 認證
從rest-assured的2.5.0版本開始,我們使用 OAuth 2 可以不依賴 scribe :
1 gien().auth().oauth2(accessToken). ..
這將會把 OAuth 2 的 accessToken 放到 header 中,如果想要使用更加顯示化的操作,可以:
1 given().auth().preemptive().oauth2(accessToken). ..
之所以還存在 given().auth().oauth2(..) 這種寫法是因為需要向后兼容實際上他們做的是相同的事情)。如果我們需要在一個查詢參數中提空 OAuth2 token 的話,那我們就需要在classpath 中引入 scribe,然后這樣寫:
1 given().auth().oauth2(accessToken, OAuthSignature.QUERY_STRING). ..
六、自定義授權
rest-assured允許我們創建自定義的授權認證提供者。我們想要實現自定義授權認證的話就需要實現 io.restassured.spi.AuthFilter 這個接口,並作為過濾器(filter)來使用它。舉個例子,假如我們的安全機制是由兩個header的值組合在一起形成一個新的叫做 "AUTH"的header(這當然是不安全的)。那么我們可以這樣寫(Java 8語法):
1 given(). 2 filter((requestSpec, responseSpec, ctx) -> { 3 String header1 = requestSpec.getHeaders().getValue("header1"); 4 String header2 = requestSpec.getHeaders().getValue("header2"); 5 requestSpec.header("AUTH", header1 + header2); 6 return ctx.next(requestSpec, responseSpec); 7 }). 8 when(). 9 get("/customAuth"). 10 then(). 11 statusCode(200);
使用 AuthFilter 而不使用 Filter 的原因是:當我們執行 given().auth().none(). ..
. 時 AuthFilter 會被自動移除。