Merge branch 'master' of https://gitee.com/youlaiorg/youlai-boot
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -106,6 +106,13 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot 4: @AutoConfigureMockMvc 移到了 webmvc-test 模块 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webmvc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
|
||||
@@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.youlai.boot.framework.mybatis.handler.AutoFillMetaObjectHandler;
|
||||
import com.youlai.boot.framework.mybatis.interceptor.MyDataPermissionHandler;
|
||||
import com.youlai.boot.framework.mybatis.MetaFieldFillHandler;
|
||||
import com.youlai.boot.framework.mybatis.MyDataPermissionHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
@@ -43,7 +43,7 @@ public class MybatisConfig {
|
||||
@Bean
|
||||
public GlobalConfig globalConfig() {
|
||||
GlobalConfig globalConfig = new GlobalConfig();
|
||||
globalConfig.setMetaObjectHandler(new AutoFillMetaObjectHandler());
|
||||
globalConfig.setMetaObjectHandler(new MetaFieldFillHandler());
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
@@ -32,8 +32,6 @@ import java.util.stream.Stream;
|
||||
@Slf4j
|
||||
public class OpenApiConfig {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final SecurityProperties securityProperties;
|
||||
|
||||
/**
|
||||
@@ -42,13 +40,10 @@ public class OpenApiConfig {
|
||||
@Bean
|
||||
public OpenAPI openApi() {
|
||||
|
||||
String appVersion = environment.getProperty("project.version", "1.0.0");
|
||||
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("管理系统 API 文档")
|
||||
.description("本文档涵盖管理系统的所有API接口,包括登录认证、用户管理、角色管理、部门管理等功能模块,提供详细的接口说明和使用指南。")
|
||||
.version(appVersion)
|
||||
.license(new License()
|
||||
.name("Apache License 2.0")
|
||||
.url("http://www.apache.org/licenses/LICENSE-2.0")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.youlai.boot.framework.mybatis.handler;
|
||||
package com.youlai.boot.framework.mybatis;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.youlai.boot.framework.security.util.SecurityUtils;
|
||||
@@ -17,7 +17,7 @@ import java.time.LocalDateTime;
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Component
|
||||
public class AutoFillMetaObjectHandler implements MetaObjectHandler {
|
||||
public class MetaFieldFillHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.youlai.boot.framework.mybatis.interceptor;
|
||||
package com.youlai.boot.framework.mybatis;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -23,7 +23,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据权限控制器
|
||||
* 数据权限处理器
|
||||
* <p>
|
||||
* 支持多角色数据权限合并(并集策略):
|
||||
* - 如果任一角色是 ALL,则跳过数据权限过滤
|
||||
@@ -4,12 +4,10 @@ spring:
|
||||
profiles:
|
||||
active: dev
|
||||
config:
|
||||
# 引入代码生成模块的配置(数据源、表前缀等),由 codegen.yml 提供
|
||||
import: classpath:codegen.yml
|
||||
servlet:
|
||||
multipart:
|
||||
# 单文件大小上限,取自 file-storage.upload.max-file-size(单一来源)
|
||||
max-file-size: ${file-storage.upload.max-file-size:50MB}
|
||||
max-request-size: ${file-storage.upload.max-file-size:50MB}
|
||||
# 在 banner.txt 中显示项目版本,使用 @project.version@ 从 pom.xml 获取
|
||||
project:
|
||||
version: @project.version@
|
||||
|
||||
@@ -7,7 +7,6 @@ ${AnsiColor.BRIGHT_BLUE}
|
||||
|_|\___/ \__,_| |______\__,_|_|
|
||||
|
||||
${AnsiColor.BRIGHT_GREEN}
|
||||
YouLai Boot Version: ${project.version}
|
||||
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
|
||||
有来官网: https://www.youlai.tech/
|
||||
版权所属: 有来开源组织
|
||||
|
||||
147
src/test/java/com/youlai/boot/AuthControllerTest.java
Normal file
147
src/test/java/com/youlai/boot/AuthControllerTest.java
Normal file
@@ -0,0 +1,147 @@
|
||||
package com.youlai.boot;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* 认证 + 当前用户接口单元测试
|
||||
*
|
||||
* @author Ray.Hao
|
||||
* @since 4.6.0
|
||||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("dev")
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class AuthControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private static String accessToken;
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@DisplayName("登录成功")
|
||||
void loginSuccess() throws Exception {
|
||||
String body = """
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "123456"
|
||||
}
|
||||
""";
|
||||
|
||||
MvcResult result = mockMvc.perform(post("/api/v1/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("00000"))
|
||||
.andExpect(jsonPath("$.data.accessToken").isString())
|
||||
.andExpect(jsonPath("$.data.refreshToken").isString())
|
||||
.andExpect(jsonPath("$.data.tokenType").value("Bearer"))
|
||||
.andExpect(jsonPath("$.data.expiresIn").isNumber())
|
||||
.andReturn();
|
||||
|
||||
JsonNode root = objectMapper.readTree(result.getResponse().getContentAsString());
|
||||
accessToken = root.path("data").path("accessToken").asText();
|
||||
|
||||
assertNotNull(accessToken, "登录后应返回 accessToken");
|
||||
assertFalse(accessToken.isBlank(), "accessToken 不能为空");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
@DisplayName("密码错误登录失败")
|
||||
void loginWithWrongPassword() throws Exception {
|
||||
String body = """
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "wrong_password"
|
||||
}
|
||||
""";
|
||||
|
||||
mockMvc.perform(post("/api/v1/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("A0210"))
|
||||
.andExpect(jsonPath("$.msg").value("密码错误"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@DisplayName("空用户名登录失败")
|
||||
void loginWithEmptyUsername() throws Exception {
|
||||
String body = """
|
||||
{
|
||||
"username": "",
|
||||
"password": "123456"
|
||||
}
|
||||
""";
|
||||
|
||||
mockMvc.perform(post("/api/v1/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("B0001"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@DisplayName("登录后获取当前用户信息")
|
||||
void getCurrentUserWithToken() throws Exception {
|
||||
assertNotNull(accessToken, "accessToken 应由登录测试先行填充");
|
||||
|
||||
mockMvc.perform(get("/api/v1/users/me")
|
||||
.header("Authorization", "Bearer " + accessToken))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("00000"))
|
||||
.andExpect(jsonPath("$.data.userId").isNumber())
|
||||
.andExpect(jsonPath("$.data.username").isString())
|
||||
.andExpect(jsonPath("$.data.nickname").isString())
|
||||
.andExpect(jsonPath("$.data.roles").isArray())
|
||||
.andExpect(jsonPath("$.data.perms").isArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
@DisplayName("无 Token 请求 /me 返回令牌无效")
|
||||
void getCurrentUserWithoutToken() throws Exception {
|
||||
mockMvc.perform(get("/api/v1/users/me"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("A0230"))
|
||||
.andExpect(jsonPath("$.msg").value("令牌无效或已过期"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
@DisplayName("伪造 Token 请求 /me 返回令牌无效")
|
||||
void getCurrentUserWithInvalidToken() throws Exception {
|
||||
mockMvc.perform(get("/api/v1/users/me")
|
||||
.header("Authorization", "Bearer invalid_token_xxx"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value("A0230"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user