2539-SpringSecurity系列--在有安全验证的情况下做单元测试Test
在有安全验证的情况下做单元测试Test
版本信息
<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单元测试-->
需求
- 在写单元测试时,需要模拟某个用户的登录状态
- 在写单元测试时,需要模拟某个用户具有某个权限,但又不想改变数据库
- 编写单元测试时,需求完整调用某个用户的登录
解决需求:
springSecurity提供了相关的组件spring-security-test,可参考官方文档(https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/reference/htmlsingle/#test-method-withmockuser),该组件提供了相关的注解来来模拟用户登录信息或者调用用户登录的方法,
- @WithMockUser 模拟用户,手动指定用户名和授权
- @WithAnonymousUser 模拟匿名用户
- @WithUserDetails 模拟用户,给定用户名,通过自定义UserDetails来认证
- @WithSecurityContext 通过SecurityContext构造器模拟用户
例如
@Test @WithMockUser(username="admin",roles={"USER","ADMIN"}) public void getMessageWithMockUserCustomUser() { String message = messageService.getMessage(); ... }
模拟了一个名叫admin的用户,拥有角色"USER","ADMIN"
代码范例
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()); } }
完整项目工程参考
分类:
SpringSecurity系列
标签:
springboot
, SpringSecurity
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~