Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在预授权(hasRole)下对spring security进行单元测试?_Java_Testing_Spring Security_Mocking - Fatal编程技术网

Java 如何在预授权(hasRole)下对spring security进行单元测试?

Java 如何在预授权(hasRole)下对spring security进行单元测试?,java,testing,spring-security,mocking,Java,Testing,Spring Security,Mocking,为了单元测试控制器方法上预授权注释的hasRole部分,我需要什么 我的测试应该成功,因为登录的用户只有两个角色中的一个,但它失败,出现以下断言错误: java.lang.AssertionError:状态 预期:401 实际:200 我在MyController中有以下方法: @PreAuthorize(value = "hasRole('MY_ROLE') and hasRole('MY_SECOND_ROLE')") @RequestMapping(value = &q

为了单元测试控制器方法上预授权注释的hasRole部分,我需要什么

我的测试应该成功,因为登录的用户只有两个角色中的一个,但它失败,出现以下断言错误:

java.lang.AssertionError:状态

预期:401

实际:200

我在MyController中有以下方法:

@PreAuthorize(value = "hasRole('MY_ROLE') and hasRole('MY_SECOND_ROLE')")
@RequestMapping(value = "/myurl", method = RequestMethod.GET)
public String loadPage(Model model, Authentication authentication, HttpSession session) {
    ...stuff to do...
}
我创建了以下abstract-security-test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <security:global-method-security secured-annotations="enabled" />

    <security:authentication-manager alias="authManager">
        <security:authentication-provider>
            <security:user-service>
                <security:user name="missingsecondrole" password="user" authorities="MY_ROLE" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>
更新 SpringSecurity4提供了与MockMvc的集成。例如:

import static org.springframework.security.test.web.servlet.setup.SecurityMockMVCConfiguers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@上下文配置
@WebAppConfiguration
公共类SecurityLockMVCTEsts{
@自动连线
私有WebApplicationContext上下文;
私有MockMvc;
@以前
公共作废设置(){
mvc=MockMvcBuilders
.webAppContextSetup(上下文)
.apply(springSecurity())
.build();
}
@试验
使用UserRequestPostProcessor()的公共void{
mvc
.perform(get(“/admin”)。使用(用户(“admin”)。角色(“用户”、“管理员”))
...
}
@WithMockUser(roles=“ADMIN”)
@试验
使用mockuser()公开void{
mvc
.perform(get(“/admin”))
...
}
...
问题

问题是设置SecurityContextHolder在此实例中不起作用。原因是SecurityContextPersistenceFilter将使用SecurityContextRepository尝试从HttpServletRequest中找出SecurityContext(默认情况下,它使用HttpSession)。它找到(或未找到)的SecurityContext将覆盖您在SecurityContextHolder上设置的SecurityContext

解决方案

要确保请求经过身份验证,您需要使用正在使用的SecurityContextRepository关联SecurityContext。默认值为HttpSessionSecurityContextRepository。下面是允许您模拟用户登录的示例方法:

private SecurityContextRepository repository = 
      new HttpSessionSecurityContextRepository();

private void login(SecurityContext securityContext, HttpServletRequest request) {
    HttpServletResponse response = new MockHttpServletResponse();

    HttpRequestResponseHolder requestResponseHolder = 
          new HttpRequestResponseHolder(request, response);
    repository.loadContext(requestResponseHolder);

    request = requestResponseHolder.getRequest();
    response = requestResponseHolder.getResponse();

    repository.saveContext(securityContext, request, response);
}
关于如何使用它的细节可能仍然有点模糊,因为您可能不知道如何在MockMvc中访问HttpServletRequest,但请继续阅读,因为有更好的解决方案

使之更容易

如果您想简化与MockMvc的交互以及其他与安全相关的交互,可以参考gs-spring-Security-3.2示例应用程序。在项目中,您将找到一些用于使用spring Security和MockMvc的实用程序。要使用它们,您可以将前面提到的类复制到您的项目中。使用此实用程序将允许您编写如下内容:

RequestBuilder request = get("/110")
    .with(user(rob).roles("USER"));

mvc
    .perform(request)
    .andExpect(status().isUnAuthorized());
注意:不需要在请求上设置主体,因为只要用户经过身份验证,Spring Security就会为您建立主体

您可以在中找到其他示例。 该项目还将协助MockMvc和Spring Security之间的其他集成(即,在执行POST时使用CSRF令牌设置请求)

默认情况下不包括?

您可能会问,为什么默认情况下不包括此内容。答案是,我们根本没有时间讨论3.2时间表。示例中的所有代码都可以正常工作,但我们对命名约定以及它如何集成以发布此版本没有足够的信心。您可以跟踪计划在Spring Security 4.0.0.M1中发布的代码

更新

您的MockMvc实例还需要包含springSecurityFilterChain

@Autowired
private Filter springSecurityFilterChain;

@Test
public void testValidUserWithInvalidRoleFails() throws Exception {
    MockMvc mockMvc = standaloneSetup(myController)
        .addFilters(springSecurityFilterChain)
        .setViewResolvers(viewResolver())
        .build();
    ...

要使
@Autowired
正常工作,您需要确保在
@ContextConfiguration
中包含使springSecurityFilterChain的安全配置。对于当前设置,这意味着“classpath:/spring/abstract security test.xml”应该包含安全配置的
部分(以及所有依赖bean)。或者,您可以在
@ContextConfiguration
中包含第二个文件,其中包含安全配置的
部分(以及所有依赖bean).

仅添加到上述Rob的解决方案中,截至2014年12月20日,主分支上的
SecurityRequestPostProcessors
类中存在一个来自Rob上述答案的bug,该bug阻止填充分配的角色

快速修复方法是注释掉
UserRequestPostProcessor的
internal static类的
roles(String…roles)
方法中的以下代码行(当前为第181行):

//列表权限=新建ArrayList(roles.length);

您需要注释掉局部变量,而不是成员变量

或者,您可以在从方法返回之前插入此行:

this.authorities=authorities;


p.S如果我有足够的声誉,我会将此作为评论添加。

MockMvcBuilders.standaloneSetup
获取手动实例化的
MyController
(没有Spring,因此没有AOP)。因此预授权不会被拦截,安全检查将被跳过。
因此,您可以@Autowire您的控制器并将其传递给
MockMvcBuilders.standaloneSetup
,以模拟传递给控制器的任何服务(有时需要)使用
@MockBean
,这样服务的每个实例都会被替换为Mock。

感谢Rob的完整解释。但是在下载gs-spring-security-3.2 3安全测试失败后:inboxShowsOnlyRobsMessages、validUsernamePassword、robCannotAccessLukesMessage。这些似乎都基于用户和角色。S同样地,实施你的建议并没有改变问题,我仍然坚持
@Autowired
private Filter springSecurityFilterChain;

@Test
public void testValidUserWithInvalidRoleFails() throws Exception {
    MockMvc mockMvc = standaloneSetup(myController)
        .addFilters(springSecurityFilterChain)
        .setViewResolvers(viewResolver())
        .build();
    ...