Playframework安全模块:您如何;“登录”;在功能测试中测试安全控制器?
编辑:我正在使用Play!版本1.2(生产版本) 我想测试由安全模块保护的控制器操作 类,因此我需要在测试控制器之前登录(否则我将被重定向到登录页面) 我已尝试在调用安全操作之前登录。下面是我的FunctionalTest的外观:Playframework安全模块:您如何;“登录”;在功能测试中测试安全控制器?,playframework,Playframework,编辑:我正在使用Play!版本1.2(生产版本) 我想测试由安全模块保护的控制器操作 类,因此我需要在测试控制器之前登录(否则我将被重定向到登录页面) 我已尝试在调用安全操作之前登录。下面是我的FunctionalTest的外观: @Test public void someTestOfASecuredAction() { Map<String, String> loginUserParams = new HashMap<String, String>();
@Test
public void someTestOfASecuredAction() {
Map<String, String> loginUserParams = new HashMap<String, String>();
loginUserParams.put("username", "admin");
loginUserParams.put("password", "admin");
// Login here so the following request will be authenticated:
Response response = POST("/login", loginUserParams);
// The following is an action that requires an authenticated user:
Map<String, String> params;
params.put("someparam", "somevalue");
response = POST("/some/secured/action", params);
assertIsOk(response); // this always fails because it is a 302 redirecting to /login
}
@测试
public void someTestOfASecuredAction(){
Map loginUserParams=new HashMap();
loginUserParams.put(“用户名”、“管理员”);
loginUserParams.put(“密码”、“管理员”);
//在此处登录,以便对以下请求进行身份验证:
响应=POST(“/login”,loginUserParams);
//以下是需要经过身份验证的用户的操作:
映射参数;
参数put(“someparam”、“somevalue”);
响应=POST(“/some/secured/action”,参数);
assertesok(response);//这总是失败的,因为它是一个302重定向到/login
}
在代码中,我已经验证了登录帖子是否有效——它会导致重定向响应,并将位置设置为主页(这表示登录成功)
但在随后的安全操作调用中,我总是被重定向到
“/login”页-表示我以前的登录没有坚持第二次POST请求
查看FunctionalTest的源代码时,我发现有一个@Before拦截器可以清除所有cookie。我尝试在我自己的中介超类中重写这个拦截器(以保存cookies),但也没有成功
编辑:我把play.mvc.Before拦截器与org.junit.Before混淆了——前者用于play!控制器,后者用于JUnit测试。Funciontest中的@Before是JUnit拦截器,因此它应该对Cookie有任何影响(因为它在运行测试之前运行一次)
我不想为每个安全操作编写Selenium测试,因为几乎所有操作都是安全的。有没有办法“愚弄”安全模块,使其相信您已通过身份验证?或者是在功能测试中处理这个(看似常见)场景的其他非常明显的方法
提前感谢,
标记
编辑:工作代码,Codemwnci的答案标记为正确
Codemwnci的答案是正确的。以下是我在从一个请求到下一个请求之间保存cookie的解决方法:
@Test
public void someTestOfASecuredAction() {
Map<String, String> loginUserParams = new HashMap<String, String>();
loginUserParams.put("username", "admin");
loginUserParams.put("password", "admin");
Response loginResponse = POST("/login", loginUserParams);
Request request = newRequest();
request.cookies = loginResponse.cookies; // this makes the request authenticated
request.url = "/some/secured/action";
request.method = "POST";
request.params.put("someparam", "somevalue");
Response response = makeRequest(request);
assertIsOk(response); // Passes!
}
@测试
public void someTestOfASecuredAction(){
Map loginUserParams=new HashMap();
loginUserParams.put(“用户名”、“管理员”);
loginUserParams.put(“密码”、“管理员”);
响应loginResponse=POST(“/login”,loginUserParams);
Request=newRequest();
request.cookies=loginResponse.cookies;//这会使请求经过身份验证
request.url=“/some/secured/action”;
request.method=“POST”;
request.params.put(“someparam”、“somevalue”);
响应=makeRequest(请求);
断言(响应);//通过!
}
我想一定是对@Before拦截器的功能有误解。它在测试执行之前执行。如果您的测试随后让您登录,则此事件发生在@Before代码执行之后,并且安全模块的结果应保存到Cookie中
因此,我只能假设Cookie没有随以下请求一起发送,因此,我建议尝试以下操作
登录后立即从响应对象获取安全cookie使用的cookie。创建一个请求对象并将Cookie设置为请求对象,然后调用POST方法,传入请求对象
我还没有测试过这段代码,所以不确定它对混合一个预构建的请求对象和传递一个URL会有什么反应,但不确定还有什么建议。也许你看到了
我认为它应该会起作用
更新:我做了一些调试。我认为有两个错误
更新2:我做了一些补丁来修复它:我想指出Mark S的最终解决方案中有一个错误 这是错误的:
request.url=“/some/secured/action”代码>
这是正确的:request.path=“/some/secured/action”代码>
“url”应该是完整的url。我也有同样的问题,但在Play 2.0.4的测试中
我通过以下步骤和答案解决了问题,并通过检查API构建了以下解决方案:
@Test
public void listSomething() {
running(fakeApplication(inMemoryDatabase()), new Runnable() {
@Override
public void run() {
// LOGIN
final Map<String, String> data = new HashMap<String, String>();
data.put("email", "user@domain.com");
data.put("password", "userpassword");
Result result = callAction(
controllers.routes.ref.Application.authenticate(),
fakeRequest().withFormUrlEncodedBody(data));
// RECOVER COOKIE FROM LOGIN RESULT
final Cookie playSession = play.test.Helpers.cookie("PLAY_SESSION",
result);
// LIST SOMETHING (using cookie of the login result)
result = callAction(controllers.routes.ref.Application.list(),
fakeRequest().withCookies(playSession));
/*
* WAS RECEIVING 'SEE_OTHER' (303)
* BEFORE RECOVERING PLAY_SESSION COOKIE (BECAUSE NOT LOGGED IN).
*
* NOW, EXPECTED 'OK'
*/
assertThat(status(result)).isEqualTo(OK);
assertThat(contentAsString(result)).contains(
"Something found");
}
});
}
我不这么认为,因为我使用的是1.2版(将添加为问题的编辑)。起初,这似乎是有可能的,但我已经通过了一个测试,通过了微管理cookies,这表明会话正在多个请求中使用。如果你阅读了关于这个bug的最后评论,即使它被认为是关闭的,它似乎仍然存在。我也在使用play 1.2,我的FunctionalTest中的每个请求都会有一个新的会话,所以我遇到了与您相同的问题。如果你看FunctionalTest的代码,这里有一个savedCookies变量,看起来它应该在请求之间保存cookie,但对我来说它不起作用。到目前为止,我一直懒得调试它,但我认为这是一个功能最差的bug。i、 e.launchpad bug基本上需要重新打开。一种理论,看起来我已经在application.conf中注释掉了:#application.session.maxAge=1h;
@Security.Authenticated(Secured.class)
public static Result list() {
return ok(list.render(...));
}