当前位置: 首页 > 面试题库 >

Spring Test & Security:如何模拟身份验证?

东郭思远
2023-03-14
问题内容

我试图弄清楚如何对我的控制器的URL进行适当安全的单元测试。以防万一有人更改周围的内容并意外删除安全设置。

我的控制器方法如下所示:

@RequestMapping("/api/v1/resource/test") 
@Secured("ROLE_USER")
public @ResonseBody String test() {
    return "test";
}

我像这样设置一个WebTestEnvironment:

import javax.annotation.Resource;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.junit.Before;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({ 
        "file:src/main/webapp/WEB-INF/spring/security.xml",
        "file:src/main/webapp/WEB-INF/spring/applicationContext.xml",
        "file:src/main/webapp/WEB-INF/spring/servlet-context.xml" })
public class WebappTestEnvironment2 {

    @Resource
    private FilterChainProxy springSecurityFilterChain;

    @Autowired
    @Qualifier("databaseUserService")
    protected UserDetailsService userDetailsService;

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    protected DataSource dataSource;

    protected MockMvc mockMvc;

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected UsernamePasswordAuthenticationToken getPrincipal(String username) {

        UserDetails user = this.userDetailsService.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken authentication = 
                new UsernamePasswordAuthenticationToken(
                        user, 
                        user.getPassword(), 
                        user.getAuthorities());

        return authentication;
    }

    @Before
    public void setupMockMvc() throws NamingException {

        // setup mock MVC
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(this.wac)
                .addFilters(this.springSecurityFilterChain)
                .build();
    }
}

在我的实际测试中,我尝试执行以下操作:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;

import eu.ubicon.webapp.test.WebappTestEnvironment;

public class CopyOfClaimTest extends WebappTestEnvironment {

    @Test
    public void signedIn() throws Exception {

        UsernamePasswordAuthenticationToken principal = 
                this.getPrincipal("test1");

        SecurityContextHolder.getContext().setAuthentication(principal);        

        super.mockMvc
            .perform(
                    get("/api/v1/resource/test")
//                    .principal(principal)
                    .session(session))
            .andExpect(status().isOk());
    }

}

JUnit如何测试@PreAuthorize批注及其由spring MVC控制器指定的spring EL?
但是,如果仔细观察,这仅在不向URL发送实际请求时才有帮助,而仅在功能级别上测试服务时才有帮助。在我的情况下,抛出了“拒绝访问”异常:

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.1.RELEASE.jar:3.2.1.RELEASE]
        ...

以下两个日志消息是值得注意的,它们基本上表明没有用户经过身份验证,表明该设置Principal无效或已被覆盖。

14:20:34.454 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List test.TestController.test(); target is of class [test.TestController]; Attributes: [ROLE_USER]
14:20:34.454 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS

问题答案:

事实证明,作为SecurityContextPersistenceFilterSpring Security过滤器链的一部分的,始终会重置my SecurityContext,而我会设置调用SecurityContextHolder.getContext().setAuthentication(principal)(或使用.principal(principal)方法)。该过滤器设置SecurityContextSecurityContextHolder同一个SecurityContextSecurityContextRepository覆盖一个我先前设置。HttpSessionSecurityContextRepository默认情况下,该存储库为。被HttpSessionSecurityContextRepository检查的给定HttpRequest并尝试访问相应的HttpSession。如果它存在,它会尝试读取SecurityContext距离HttpSession。如果失败,则存储库将生成一个empty SecurityContext

因此,我的解决方案是将HttpSession连同请求一起传递,其中包含SecurityContext

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;

import eu.ubicon.webapp.test.WebappTestEnvironment;

public class Test extends WebappTestEnvironment {

    public static class MockSecurityContext implements SecurityContext {

        private static final long serialVersionUID = -1386535243513362694L;

        private Authentication authentication;

        public MockSecurityContext(Authentication authentication) {
            this.authentication = authentication;
        }

        @Override
        public Authentication getAuthentication() {
            return this.authentication;
        }

        @Override
        public void setAuthentication(Authentication authentication) {
            this.authentication = authentication;
        }
    }

    @Test
    public void signedIn() throws Exception {


 类似资料:
  • 我正在使用spring security 5和spring boot 2.0.0 我有一个测试配置文件。 我有springBootApplication文件。 安全日志在下面

  • 我在我的控制器中有一个方法如下所示: 我有一个500的误差。 我尝试过的控制器的另一个变体是,它适用于postman/curl:

  • 我试图弄清楚如何进行单元测试,如果我的控制器的URL是正确的安全的。以防万一有人改变了周围的东西,不小心移除了安全设置。 我的controller方法如下所示: 我设置了一个WebTestEnvironment,如下所示: null 然而,如果仔细观察,这只在不向URL发送实际请求时才有帮助,而只在功能级别上测试服务时才有帮助。在我的案例中,抛出了“拒绝访问”异常: 以下两条日志消息值得注意,基本

  • 我正在开发一个Web应用程序 然而,我在尝试允许用户通过注册链接注册时遇到了一个问题。如果用户未经身份验证,则无法访问注册表的链接(“showRegistrationForm”) 有人能洞察为什么会发生这种情况吗?我在下面包含了我的安全配置中的代码片段

  • 我必须说,我对整个模型非常困惑,我需要帮助把所有的浮动件粘在一起。 我不是在做Spring REST,只是简单的WebMVC控制器。 什么让人困惑?(错误之处请指正) 第三方身份验证 要针对第三方进行身份验证,我需要通过扩展AuthenticationProvider来拥有自定义提供程序 null 问题: 何时调用AbstractAuthenticationProcessingFilter#Suc

  • 我很难让LDAP安全配置与xml配置一起工作。