2539-SpringSecurity系列--在有安全驗證的狀況下作單元測試Test

在有安全驗證的狀況下作單元測試Testhtml

版本信息

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.14.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>1.5.14.RELEASE</version>
    <!--實際裏面spring-security-web的版本是4.2.7-->
</dependency>

添加依賴

<!--spring-security單元測試-->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>4.2.3.RELEASE</version>
    <scope>test</scope>
</dependency>
<!--spring-security單元測試-->

需求

  1. 在寫單元測試時,須要模擬某個用戶的登陸狀態
  2. 在寫單元測試時,須要模擬某個用戶具備某個權限,但又不想改變數據庫
  3. 編寫單元測試時,需求完整調用某個用戶的登陸

解決需求:

springSecurity提供了相關的組件spring-security-test,可參考官方文檔(https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/reference/htmlsingle/#test-method-withmockuser),該組件提供了相關的註解來來模擬用戶登陸信息或者調用用戶登陸的方法java

  • @WithMockUser 模擬用戶,手動指定用戶名和受權
  • @WithAnonymousUser 模擬匿名用戶
  • @WithUserDetails 模擬用戶,給定用戶名,經過自定義UserDetails來認證
  • @WithSecurityContext 經過SecurityContext構造器模擬用戶

例如git

@Test
@WithMockUser(username="admin",roles={"USER","ADMIN"})
public void getMessageWithMockUserCustomUser() {
    String message = messageService.getMessage();
    ...
}

模擬了一個名叫admin的用戶,擁有角色"USER","ADMIN"github

代碼範例

import com.alibaba.fastjson.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;

import java.util.HashMap;
import java.util.Map;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * 接口測試+ SpringSecurity的用戶登陸模擬
 */
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
@Rollback(true)// 事務自動回滾,默認是true。能夠不寫
public class ExampleRestClientTest {


    private MockMvc mockMvc; // 模擬MVC對象,經過MockMvcBuilders.webAppContextSetup(this.wac).build()初始化。

    @Autowired
    private WebApplicationContext wac; // 注入WebApplicationContext

    @Before // 在測試開始前初始化工做
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
    }

    @Test
    @WithUserDetails(value = "admin", userDetailsServiceBeanName = "customUserDetailsService")
    public void testQ1() throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("param1", "valueaa");

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/secmenu/getUserMenuList")
                .contentType(MediaType.APPLICATION_JSON_UTF8).content(JSONObject.toJSONString(map)))
                .andExpect(status().is(200))// 模擬向testRest發送get請求
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))// 預期返回值的媒體類型text/plain;charset=UTF-8
                .andReturn();// 返回執行請求的結果

    }

    @Test
    public void testFormLoginSuccess() throws Exception {

        // 測試登陸成功
        mockMvc
                .perform(formLogin("/login").user("admin").password("123456"))
                .andExpect(authenticated());
    }

    @Test
    public void testFormLoginFail() throws Exception {
        // 測試登陸失敗
        mockMvc
                .perform(formLogin("/login").user("admin").password("invalid"))
                .andExpect(unauthenticated());
    }

    @Test
    public void testLogoutFail() throws Exception {
        // 測試退出登陸
        mockMvc.perform(logout("/logout")).andExpect(unauthenticated());
    }
}

完整項目工程參考

https://github.com/starmoon1994/springsecurity-collectionweb

相關文章
相關標籤/搜索