用于 Selenium 测试的 Spring Security @WithMockUser

Posted

技术标签:

【中文标题】用于 Selenium 测试的 Spring Security @WithMockUser【英文标题】:Spring Security @WithMockUser for Selenium test 【发布时间】:2015-07-14 02:41:29 【问题描述】:

我刚刚发现了新的 Spring Security 4 测试注释 @WithMockUser,但我无法让它用于我的 Selenium 测试。 问题是,这个注解创建了一个模拟 SecurityContext,但是一个新的是由 HttpSessionSecurityContextRepository 创建的,因为 Selenium 基于一个真实的浏览器运行测试。 我能否以某种方式告诉 Spring 使用模拟 SecurityContext 作为下一个会话安全上下文?

谢谢!

【问题讨论】:

【参考方案1】:

我找到了在测试类路径中使用新过滤器对模拟用户进行身份验证的方法:

@Component
public class MockUserFilter extends GenericFilterBean 

    @Autowired
    private UserDetailsService userDetailsService;

    private SecurityContext securityContext;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException 
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (securityContext != null) 
            SecurityContextRepository securityContextRepository = WebTestUtils.getSecurityContextRepository(request);

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

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

            securityContextRepository.saveContext(securityContext, request, response);

            securityContext = null;
        
        chain.doFilter(request, response);
    

    public void authenticateNextRequestAs(String username) 
        UserDetails principal = userDetailsService.loadUserByUsername(username);
        Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
        securityContext = SecurityContextHolder.createEmptyContext();
        securityContext.setAuthentication(authentication);
    

它的灵感来自SecurityMockMvcRequestPostProcessorsWithUserDetailsSecurityContextFactory

我无法使用 @WithUserDetails 注释,因为我运行 Cucumber 测试,但使用此过滤器,我可以在一行中模拟下一个请求的身份验证:testSecurityFilter.authenticateNextRequestAs("username");

【讨论】:

你有完整的例子吗?【参考方案2】:

我添加此答案是因为虽然接受的答案帮助我形成了解决方案,但我必须进行一些更改才能使其正常工作。这个答案也帮助我让它工作:https://***.com/a/8336233/2688076

这是我的 MockUserFilter:

        @Component("MockUserFilter")
        public class MockUserFilter extends GenericFilterBean 
            @Autowired
            private UserDetailService userDetailService;

            private SecurityContext securityContext;

            @Autowired
            private AuthenticationProvider authenticationProvider;

            public void setUserDetailService(UserDetailService userDetailService) 
                this.userDetailService = userDetailService;
            
            @Override
            public void doFilter(ServletRequest request, ServletResponse response,
                    FilterChain chain) throws IOException, ServletException 
                HttpServletRequest servletRequest = (HttpServletRequest) request;
                HttpServletResponse servletResponse = (HttpServletResponse) response;

                if (securityContext != null) 
                    SecurityContextRepository securityContextRepository = WebTestUtils.getSecurityContextRepository(servletRequest);
                    HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(servletRequest, servletResponse);
                    securityContextRepository.loadContext(requestResponseHolder);
                    servletRequest = requestResponseHolder.getRequest();
                    servletResponse = requestResponseHolder.getResponse();
                    securityContextRepository.saveContext(securityContext, servletRequest, servletResponse);
                    securityContext = null;
                

                chain.doFilter(request, response);
            

             public void authenticateNextRequestAs(String username, ServletRequest request) 
                 UserDetails principal = userDetailService.loadUserByUsername(username);
                 Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
                 securityContext = SecurityContextHolder.createEmptyContext();
                 securityContext.setAuthentication(authentication);
                 SecurityContextHolder.getContext().setAuthentication(authentication);

                 HttpSession session = ((HttpServletRequest) request).getSession(true);
                 session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
            
        

除此之外,我还必须从过滤器链中删除我的 casAuthenticationFilter 才能使其正常工作。我使用属性值来启用/禁用它。

我对 Spring 和 Spring 安全性比较陌生,因此欢迎使用此解决方案的任何 cmets。我不确定这个解决方案有多“好”或“坏”。

要记住的一点是,这是一种用于本地测试或在安全环境中进行测试的解决方案,而不是您在开发环境中想要的解决方案。

【讨论】:

以上是关于用于 Selenium 测试的 Spring Security @WithMockUser的主要内容,如果未能解决你的问题,请参考以下文章

python-Selenium库的详解

golang从入门到精通,搭建本地selenium自动化测试环境

关于selenium2的那些事

python selenium自动化测试

用于使用 selenium 循环 JS 路径选择器

测试那些事儿—selenium IDE 自动化测试