diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java index ec159e0ec..272419c09 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.framework.tenant.core.web; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; @@ -24,9 +24,9 @@ public class TenantContextWebFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 设置 - String tenantId = request.getHeader(HEADER_TENANT_ID); - if (StrUtil.isNotEmpty(tenantId)) { - TenantContextHolder.setTenantId(Long.valueOf(tenantId)); + Long tenantId = WebFrameworkUtils.getTenantId(request); + if (tenantId != null) { + TenantContextHolder.setTenantId(tenantId); } try { chain.doFilter(request, response); diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java index dc8533f96..bfd441160 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java @@ -105,17 +105,6 @@ public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsA return selectService(request).verifyTokenAndRefresh(token); } - /** - * 模拟指定用户编号的 LoginUser - * - * @param request 请求 - * @param userId 用户编号 - * @return 登录用户 - */ - public LoginUser mockLogin(HttpServletRequest request, Long userId) { - return selectService(request).mockLogin(userId); - } - /** * 基于 token 退出登录 * diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java index 0908560c8..cf0ee7a23 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import lombok.RequiredArgsConstructor; import org.springframework.web.filter.OncePerRequestFilter; @@ -38,12 +39,13 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { throws ServletException, IOException { String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); if (StrUtil.isNotEmpty(token)) { + Integer userType = WebFrameworkUtils.getLoginUserType(request); try { // 验证 token 有效性 LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token); // 模拟 Login 功能,方便日常开发调试 if (loginUser == null) { - loginUser = mockLoginUser(request, token); + loginUser = mockLoginUser(request, token, userType); } // 设置当前用户 if (loginUser != null) { @@ -67,9 +69,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { * * @param request 请求 * @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号 + * @param userType 用户类型 * @return 模拟的 LoginUser */ - private LoginUser mockLoginUser(HttpServletRequest request, String token) { + private LoginUser mockLoginUser(HttpServletRequest request, String token, Integer userType) { if (!securityProperties.getMockEnable()) { return null; } @@ -77,8 +80,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { if (!token.startsWith(securityProperties.getMockSecret())) { return null; } + // 构建模拟用户 Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length())); - return authenticationProvider.mockLogin(request, userId); + return new LoginUser().setId(userId).setUserType(userType) + .setTenantId(WebFrameworkUtils.getTenantId(request)); } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java index 1f76e161f..11370a3d4 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java @@ -20,14 +20,6 @@ public interface SecurityAuthFrameworkService extends UserDetailsService { */ LoginUser verifyTokenAndRefresh(String token); - /** - * 模拟指定用户编号的 LoginUser - * - * @param userId 用户编号 - * @return 登录用户 - */ - LoginUser mockLogin(Long userId); - /** * 基于 token 退出登录 * diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index a6f932dd0..a7c5b7a53 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; import cn.iocoder.yudao.framework.web.core.filter.XssFilter; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -65,6 +66,13 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { return new GlobalResponseBodyHandler(); } + @Bean + @SuppressWarnings("InstantiationOfUtilityClass") + public WebFrameworkUtils webFrameworkUtils(WebProperties webProperties) { + // 由于 WebFrameworkUtils 需要使用到 webProperties 属性,所以注册为一个 Bean + return new WebFrameworkUtils(webProperties); + } + // ========== Filter 相关 ========== /** diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java index 273f34072..b3a7f7ecb 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.framework.web.core.util; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.web.config.WebProperties; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -21,16 +23,43 @@ public class WebFrameworkUtils { private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result"; + private static final String HEADER_TENANT_ID = "tenant-id"; + + private static WebProperties properties; + + public WebFrameworkUtils(WebProperties webProperties) { + WebFrameworkUtils.properties = webProperties; + } + + /** + * 获得租户编号,从 header 中 + * 考虑到其它 framework 组件也会使用到租户编号,所以不得不放在 WebFrameworkUtils 统一提供 + * + * @param request 请求 + * @return 租户编号 + */ + public static Long getTenantId(HttpServletRequest request) { + String tenantId = request.getHeader(HEADER_TENANT_ID); + return StrUtil.isNotEmpty(tenantId) ? Long.valueOf(tenantId) : null; + } + public static void setLoginUserId(ServletRequest request, Long userId) { request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId); } + /** + * 设置用户类型 + * + * @param request 请求 + * @param userType 用户类型 + */ public static void setLoginUserType(ServletRequest request, Integer userType) { request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType); } /** * 获得当前用户的编号,从请求中 + * 注意:该方法仅限于 framework 框架使用!!! * * @param request 请求 * @return 用户编号 @@ -43,7 +72,8 @@ public class WebFrameworkUtils { } /** - * 获得当前用户的类型,从请求中 + * 获得当前用户的类型 + * 注意:该方法仅限于 web 相关的 framework 组件使用!!! * * @param request 请求 * @return 用户编号 @@ -52,7 +82,19 @@ public class WebFrameworkUtils { if (request == null) { return null; } - return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE); + // 1. 优先,从 Attribute 中获取 + Integer userType = (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE); + if (userType == null) { + return null; + } + // 2. 其次,基于 URL 前缀的约定 + if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) { + return UserTypeEnum.ADMIN.getValue(); + } + if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) { + return UserTypeEnum.MEMBER.getValue(); + } + return null; } public static Integer getLoginUserType() { diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index b79e55830..c58a6d74d 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -211,21 +211,6 @@ public class MemberAuthServiceImpl implements MemberAuthService { return userSessionApi.getLoginUser(token); } - @Override - public LoginUser mockLogin(Long userId) { - // 获取用户编号对应的 UserDO - MemberUserDO user = userService.getUser(userId); - if (user == null) { - throw new UsernameNotFoundException(String.valueOf(userId)); - } - - // 执行登陆 - createLoginLog(userId, user.getMobile(), LoginLogTypeEnum.LOGIN_MOCK, LoginResultEnum.SUCCESS); - - // 创建 LoginUser 对象 - return buildLoginUser(user); - } - @Override public void logout(String token) { // 查询用户信息 diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java index 2f845fd10..ab9d0bbbd 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java @@ -12,7 +12,6 @@ public enum LoginLogTypeEnum { LOGIN_USERNAME(100), // 使用账号登录 LOGIN_SOCIAL(101), // 使用社交登录 - LOGIN_MOCK(102), // 使用 Mock 登录 LOGIN_MOBILE(103), // 使用手机登陆 LOGIN_SMS(104), // 使用短信登陆 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http index e6c70f9df..c2715634e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http @@ -1,5 +1,5 @@ ### 请求 /login 接口 => 成功 -POST {{baseUrl}}/system/login +POST {{baseUrl}}/system/auth/login Content-Type: application/json tenant-id: {{adminTenentId}} @@ -11,7 +11,7 @@ tenant-id: {{adminTenentId}} } ### 请求 /login 接口 => 成功(无验证码) -POST {{baseUrl}}/system/login +POST {{baseUrl}}/system/auth/login Content-Type: application/json tenant-id: {{adminTenentId}} @@ -21,7 +21,7 @@ tenant-id: {{adminTenentId}} } ### 请求 /get-permission-info 接口 => 成功 -GET {{baseUrl}}/system/get-permission-info +GET {{baseUrl}}/system/auth/get-permission-info Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index ab8cc9658..475966403 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -82,19 +82,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { return AuthConvert.INSTANCE.convert2(user); } - @Override - public LoginUser mockLogin(Long userId) { - // 获取用户编号对应的 AdminUserDO - AdminUserDO user = userService.getUser(userId); - if (user == null) { - throw new UsernameNotFoundException(String.valueOf(userId)); - } - createLoginLog(userId, user.getUsername(), LoginLogTypeEnum.LOGIN_MOCK, LoginResultEnum.SUCCESS); - - // 创建 LoginUser 对象 - return buildLoginUser(user); - } - @Override public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) { // 判断验证码是否正确 diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java index 0cb376668..e13570a2b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java @@ -96,32 +96,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest { username); // 异常提示为 username } - @Test - public void testMockLogin_success() { - // 准备参数 - Long userId = randomLongId(); - // mock 方法 01 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); - when(userService.getUser(eq(userId))).thenReturn(user); - - // 调用 - LoginUser loginUser = authService.mockLogin(userId); - // 断言 - AssertUtils.assertPojoEquals(user, loginUser, "updateTime"); - } - - @Test - public void testMockLogin_userNotFound() { - // 准备参数 - Long userId = randomLongId(); - // mock 方法 - - // 调用, 并断言异常 - assertThrows(UsernameNotFoundException.class, // 抛出 UsernameNotFoundException 异常 - () -> authService.mockLogin(userId), - String.valueOf(userId)); // 异常提示为 userId - } - @Test public void testLogin_captchaNotFound() { // 准备参数