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单元测试-->

需求

  1. 在写单元测试时,需要模拟某个用户的登录状态
  2. 在写单元测试时,需要模拟某个用户具有某个权限,但又不想改变数据库
  3. 编写单元测试时,需求完整调用某个用户的登录

解决需求:

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());
    }
}

完整项目工程参考

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

原文地址:https://www.cnblogs.com/starmoon1994/p/9362333.html

时间: 2024-11-07 13:43:57

2539-SpringSecurity系列--在有安全验证的情况下做单元测试Test的相关文章

AngularJs 入门系列-2 表单验证

对于日常的开发来说,最常见的开发场景就是通过表单编辑数据,这里涉及的问题就是验证问题. angularjs 内置已经支持了常见的验证方式,可以轻松实现表单验证. 1. 绑定 为了方便,我们在 $scope 上下文对象上创建一个 model 来表示我们编辑的内容. $scope.model = { id : 8, name: "alice", email: "[email protected]" }; angularjs 的验证需要表单的配合,为了能够访问表单,我们需

MVVM架构~knockoutjs系列之扩展ajax验证~验证输入数据是否与后台数据相等

返回目录 在看这篇文章之前,你有必要先看我之前的文章,之前文章是将一个方法以参数的形式传给KO,然后返回一个真假值,去做验证,这类似于面向对象语言里的委托,在JS里我们叫它回调方法,本篇文章与前一文章不同,需要有两个参数,其一是远程方法的签名(JS方法),其二是已知要比较的数据(可能是加密后的密码数据),当用户输入文字后,它将会调用JS方法获取远程数据,以比较原数据与你输入的数据是否匹配. 知识点:以对象作为参数进行传递 ko.validation.js的扩展 //ajax相等验证 kv.rul

[Teamcenter 2007 开发系列] web 非空验证

前言 TC 2007 的Web 端,页面简洁也简单. 非空验证的话,直接在后面加上一个 红箭头+ "Required value is not specified." 这样一些红色的提示信息. 而这种验证看上去又是和CF端的form 的定义管理起来的. 定义成require 的属性会做这种验证. 那么在web 端实现的机制是怎样的呢? 是否可以不和CF端绑定,在 Web端直接进行这种验证呢? 实现机制 以创建一个物件为例,关键的action-component 是 ModelEntit

EMVTag系列5——8E 持卡人验证方法(CVM)列表

L: var. up to 252 -R(需求):数据必须存在,在读应用数据过程中,终端不检查 按照优先顺序列出卡片应用支持的所有持卡人验证方法 注:一个应用中可以有多个CVM列表,例如一个用于国内交易,一个用于国际交易 字节1–4: 金额X(二进制) 字节5–8: 金额Y(二进制) 字节9 (CVMCode): bit 8: 0 = 只有符合此规范的取值(如果不为1,说明有自定义的值) bit 7: 1 = 如果此CVM失败,应用后续的 0 = 如果此CVM失败,则持卡人验证失败 bits 6

前端测试框架Jest系列教程 -- Expect(验证)

写在前面 在编写测试时,我们通常需要检查值是否满足某些条件,Jest中提供的expect允许你访问很多“Matchers”,这些“匹配器”允许您验证不同的东西. Expect 可以验证什么 Jest中提供了如下的验证方法: expect(value) expect.extend(matchers) expect.anything() expect.any(constructor) expect.arrayContaining(array) expect.assertions(number) ex

【FICO系列】SAP FI验证故障排除(调试)

公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[FICO系列]SAP FI验证故障排除(调试) 前言部分 大家可以关注我的公众号,公众号里的排版更好,阅读更舒适. 正文部分 今天分享一篇分析调试期间FI发布中的验证. 第一步 执行事务代码:“GGB0”,这将显示所有验证定义. 第二步 找到自己的验证定义.(在我们的示例中,我们在行项目级别使用FI验证).单击验证定义,然后在命令字段中输入“=

清华EMBA课程系列思考之六 -- 比較文明视野下的中华领导智慧、企业管理与经济解析

告别马年的最后一缕阳光,踏着猴年的钟声,度过了温馨的春节,已然开启了新学期的第一堂课.看题目其貌不扬,但一旦进入课堂,已然聚精会神.唯恐掉队,就请大家跟我一起进入四天的心路修炼旅程,開始我们的新一期思考吧. -- 清华大学人文学院历史系教授 博导  教育部长江学者特聘教授 张国刚 教授 第一天:比較文明视野下的中华领导智慧 透过历史看到个人.看待事物.看待社会.看待人生,我们的推断都是基于历史.历史也是自我的经验知识库: 国学 - 经.史.子.集. 四部之学 --  仁义之道.不能以攻天下之法来

JavaScript进阶系列04,函数参数个数不确定情况下的解决方案

本篇主要体验函数参数个数不确定情况下的一个解决方案.先来看一段使用函数作为参数进行计算的实例. var calculate = function(x, y, fn) { return fn(x, y); }; var sum = function(x, y) { return x + y; }; var diff = function(x, y) { return x - y; }; var sumResult = calculate(1, 2, sum), diffResult = calcu

2016/7/20 12:17:54 MariaDB 默认情况下,无法验证密码

1. System information: [[email protected] MgmtStatus]# cat /etc/redhat-release Red Hat Enterprise Linux Server release 7.2 (Maipo) [[email protected] MgmtStatus]# uname -a Linux mgt 3.10.0-327.el7.x86_64 #1 SMP Thu Oct 29 17:29:29 EDT 2015 x86_64 x86