瀏覽代碼

简化 mock login 模拟登录的实现,由 TokenAuthenticationFilter 直接实现

YunaiV 2 年之前
父節點
當前提交
baadb5a937
共有 11 個文件被更改,包括 67 次插入86 次删除
  1. 4 4
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java
  2. 0 11
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java
  3. 8 3
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java
  4. 0 8
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java
  5. 8 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
  6. 44 2
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
  7. 0 15
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
  8. 0 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java
  9. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
  10. 0 13
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  11. 0 26
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java

+ 4 - 4
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);

+ 0 - 11
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 退出登录
      *

+ 8 - 3
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));
     }
 
 }

+ 0 - 8
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 退出登录
      *

+ 8 - 0
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 相关 ==========
 
     /**

+ 44 - 2
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() {

+ 0 - 15
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) {
         // 查询用户信息

+ 0 - 1
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), // 使用短信登陆
 

+ 3 - 3
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}}
 

+ 0 - 13
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) {
         // 判断验证码是否正确

+ 0 - 26
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() {
         // 准备参数