簡體   English   中英

無法在控制器Spring-boot中測試身份驗證所需的方法

[英]Can't test authenticate-required method in controller Spring-boot

問題:當我嘗試測試身份驗證所需的方法(使用MockUser)時,返回403錯誤,我丟失了某些內容,嘗試了幾種方法,但它們不起作用。 我不明白為什么會這樣,有人可以解釋嗎?

例如,我創建了一個簡單的應用程序來演示這一點。

春季安全配置類

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringConfigure extends WebSecurityConfigurerAdapter {


@Override
protected void configure(HttpSecurity http) throws Exception {
    configureAuthorization(http);
    configureAuthentication(http);
     }



private void configureAuthorization(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/api/**").authenticated();
    }


private void configureAuthentication(HttpSecurity http) throws Exception {
    AuthenticationEntryPoint authenticationEntryPoint = (request, response, e) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
    }
}

控制器類

@RestController
@RequestMapping("api/hello")
public class HelloController {

@RequestMapping(method = RequestMethod.GET)
public String hello(){
    return "Hello";
   }
}

和我的考試班

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DemoApplication.class},webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class DemoApplicationTests {

RestTemplate restTemplate;

@Before
public void setUp(){
    restTemplate = new RestTemplate();
   }

@Test
@WithMockUser(username = "user")
public void helloTest() {
    System.out.println(SecurityContextHolder.getContext().getAuthentication());
    ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/api/hello",String.class);
   }
}

@WithMockUser創建的用戶

Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER

我運行您的測試代碼,看來還可以。

@Test
@WithMockUser(username = "user")
public void helloTest() {
System.out.println(SecurityContextHolder.getContext().getAuthentication());
    ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/api/hello",String.class);
   }
}
System.out.println(responseEntity);

結果:

org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca25360: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER
<200,Hello

經過很多時間,我在這里找到了答案https://stackoverflow.com/a/15203488/8664578 (非常感謝),然后重復這個答案( https://stackoverflow.com/a/23658269/8664578)-測試身份驗證所需方法的最簡單方法是:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DemoApplication.class},webEnvironment = 
SpringBootTest.WebEnvironment.DEFINED_PORT)

@Autowired
private WebApplicationContext context;
@Before
public void setup() {
    mvc = MockMvcBuilders
          .webAppContextSetup(context)
          .apply(springSecurity())  
          .build();
   }

public class DemoApplicationTests {
@Test
@WithMockUser
public void helloTest() {
mockMvc.perform(MockMvcRequestBuilders.get("http://localhost:8080/api/hello")).andExpect(status().isOk());
    }
}

但是在開始時,我的問題是如何使用RestTemplate進行操作,我使用帖子中提出的解決方案,答案稍有改變(不是最好,但是解決方案)。 根據上面的鏈接:

“ HttpSessionSecurityContextRepository檢查給定的HttpRequest並嘗試訪問相應的HttpSession。如果存在,它將嘗試從HttpSession讀取SecurityContext。如果失敗,則存儲庫將生成一個空的SecurityContext。”

我們可以向filterChain添加一個過濾器,該過濾器將使用我們想要的Spring上下文添加session屬性,如下例所示:

public class CustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("user","password", 
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
   SecurityContextHolder.getContext().setAuthentication(authenticationToken);

    HttpServletRequest httpServletRequest = (HttpServletRequest) request;

    HttpSession session = httpServletRequest.getSession();
    session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
            SecurityContextHolder.getContext());

    chain.doFilter(request,response);
}

@Override
public void destroy() {

   }
}

另外,我們需要向@Configuration類添加過濾器,如下所示:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringConfigure extends WebSecurityConfigurerAdapter {


@Override
protected void configure(HttpSecurity http) throws Exception {
  configureAuthorization(http);
  configureAuthentication(http);
 }



private void configureAuthorization(HttpSecurity http) throws Exception {
  http.authorizeRequests().antMatchers("/api/**").authenticated().and().addFilterBefore(new CustomFilter(), SecurityContextPersistenceFilter.class);
}


private void configureAuthentication(HttpSecurity http) throws Exception {
AuthenticationEntryPoint authenticationEntryPoint = (request, response, e) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
  }
}

最后測試課:

@Test
public void helloTest() {
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/api/hello",String.class);
  }
}

希望對別人有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM