From 928b7dbe23338127834ae6023d2a5ae32a16308e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 28 Jan 2022 20:21:01 +0800 Subject: [PATCH] 多模块重构 2:在 yudao-admin-server 中,引入 yudao-module-member 模块 --- yudao-admin-server/pom.xml | 7 +++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java | 3 ++- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java | 19 ++++++++++++++----- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java | 14 +++++++++++--- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java | 18 ++++++++++-------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java | 3 ++- yudao-admin-server/src/main/resources/application-local.yaml | 12 ++++++++++++ yudao-admin-server/src/main/resources/application.yaml | 18 +++++++++++++++--- yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java | 1 - yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsCoreServiceImpl.java | 13 +++++-------- yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java | 3 ++- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java | 23 ++++++++++++++++++----- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java | 32 ++++++++++++++++++++------------ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java | 17 ++++++++--------- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java | 10 ++++------ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java | 10 +++++++++- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java | 10 +++++++--- yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java | 55 ++++++++++++++++++++++++++++++++++--------------------- yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java | 17 +++++++++++++---- yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java | 20 -------------------- yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java | 20 ++++++++++++++++++++ yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java | 32 -------------------------------- yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java | 32 ++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/pom.xml | 33 +++++---------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java | 30 ++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java | 9 +++++---- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java | 4 +++- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java | 27 +++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java | 1 + yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppSendSmsReqVO.java | 27 --------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java | 37 ++++++++++++++++++------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java | 2 ++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java | 23 +++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/SysAuthConvert.java | 23 ----------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java | 7 +++++-- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java | 70 ---------------------------------------------------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java | 3 +-- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MbrUserMapper.java | 19 ------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java | 19 +++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java | 2 ++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java | 3 +++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/security/SecurityConfiguration.java | 29 ----------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthService.java | 78 ------------------------------------------------------------------------------ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceImpl.java | 356 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/package-info.java | 1 - yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java | 5 ++--- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java | 41 ++++++++++++++++++----------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserService.java | 81 --------------------------------------------------------------------------------- yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImpl.java | 162 ------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java | 42 ++++++++++++++++++++---------------------- yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/package-info.java | 1 - yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java | 60 +++++++++++++++++++++++------------------------------------- yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java | 1 - yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml | 5 +++++ yudao-user-server/src/main/resources/application-dev.yaml | 13 +++++++++++++ yudao-user-server/src/main/resources/application.yaml | 7 +------ 68 files changed, 1301 insertions(+), 1139 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java create mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java delete mode 100644 yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java create mode 100644 yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java delete mode 100644 yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java create mode 100644 yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppSendSmsReqVO.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/SysAuthConvert.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MbrUserMapper.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/security/SecurityConfiguration.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthService.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceImpl.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/package-info.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserService.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImpl.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java create mode 100644 yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java delete mode 100644 yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/package-info.java diff --git a/yudao-admin-server/pom.xml b/yudao-admin-server/pom.xml index 847e626..4094369 100644 --- a/yudao-admin-server/pom.xml +++ b/yudao-admin-server/pom.xml @@ -17,6 +17,13 @@ https://github.com/YunaiV/ruoyi-vue-pro + + + cn.iocoder.boot + yudao-module-member-impl + ${revision} + + cn.iocoder.boot diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java index 8108697..35f6a1d 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java @@ -4,7 +4,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package} -@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"}) +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}", + "${yudao.info.member-package}"}) // TODO 芋艿:重构 public class AdminServerApplication { public static void main(String[] args) { diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java index e99c106..a5086b9 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java @@ -23,19 +23,28 @@ public class SecurityConfiguration { public Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() { return registry -> { // 验证码的接口 - registry.antMatchers(api("/system/captcha/**")).anonymous(); + registry.antMatchers(buildAdminApi("/system/captcha/**")).anonymous(); // 获得租户编号的接口 - registry.antMatchers(api("/system/tenant/get-id-by-name")).anonymous(); + registry.antMatchers(buildAdminApi("/system/tenant/get-id-by-name")).anonymous(); // Spring Boot Admin Server 的安全配置 registry.antMatchers(adminSeverContextPath).anonymous() .antMatchers(adminSeverContextPath + "/**").anonymous(); // 短信回调 API - registry.antMatchers(api("/system/sms/callback/**")).anonymous(); + registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous(); + + // 设置 App API 无需认证 + registry.antMatchers(buildAppApi("/**")); }; } - private String api(String url) { - return webProperties.getApiPrefix() + url; + private String buildAdminApi(String url) { + // TODO 芋艿:多模块 + return webProperties.getAdminApi().getPrefix() + url; + } + + private String buildAppApi(String url) { + // TODO 芋艿:多模块 + return webProperties.getAppApi().getPrefix() + url; } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java index ccb7cad..c18893f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java @@ -11,10 +11,12 @@ import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService; import org.activiti.api.runtime.shared.identity.UserGroupManager; +import org.activiti.core.common.spring.identity.ActivitiUserGroupManagerImpl; import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.userdetails.UserDetailsService; import java.util.Collections; import java.util.List; @@ -28,7 +30,15 @@ import static org.activiti.spring.boot.ProcessEngineAutoConfiguration.BEHAVIOR_F public class BpmActivitiConfiguration { /** - * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类,主要设置各种监听器、用户组管理 + * 空用户组的 Bean + */ + @Bean + public UserGroupManager userGroupManager() { + return new EmptyUserGroupManager(); + } + + /** + * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类,主要设置各种监听器 */ @Bean public ProcessEngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer( @@ -36,8 +46,6 @@ public class BpmActivitiConfiguration { return configuration -> { // 注册监听器,例如说 BpmActivitiEventListener configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener)); - // 用户组 - configuration.setUserGroupManager(new EmptyUserGroupManager()); }; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java index 438bd1e..3f795f8 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java @@ -60,8 +60,6 @@ import static java.util.Collections.singleton; @Slf4j public class SysAuthServiceImpl implements SysAuthService { - private static final UserTypeEnum USER_TYPE_ENUM = UserTypeEnum.ADMIN; - @Resource @Lazy // 延迟加载,因为存在相互依赖的问题 private AuthenticationManager authenticationManager; @@ -83,7 +81,6 @@ public class SysAuthServiceImpl implements SysAuthService { @Resource private SysSocialCoreService socialService; - @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 获取 username 对应的 SysUserDO @@ -216,7 +213,7 @@ public class SysAuthServiceImpl implements SysAuthService { // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错 String unionId = socialService.getAuthUserUnionId(authUser); - List socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, USER_TYPE_ENUM); + List socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType()); if (CollUtil.isEmpty(socialUsers)) { throw exception(AUTH_THIRD_LOGIN_NOT_BIND); } @@ -232,7 +229,7 @@ public class SysAuthServiceImpl implements SysAuthService { LoginUser loginUser = this.buildLoginUser(user); // 绑定社交用户(更新) - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM); + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType()); // 缓存登录用户到 Redis 中,返回 sessionId 编号 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); @@ -248,7 +245,7 @@ public class SysAuthServiceImpl implements SysAuthService { LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); // 绑定社交用户(新增) - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM); + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType()); // 缓存登录用户到 Redis 中,返回 sessionId 编号 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); @@ -261,7 +258,7 @@ public class SysAuthServiceImpl implements SysAuthService { Assert.notNull(authUser, "授权用户不为空"); // 绑定社交用户(新增) - socialService.bindSocialUser(userId, reqVO.getType(), authUser, USER_TYPE_ENUM); + socialService.bindSocialUser(userId, reqVO.getType(), authUser, getUserType()); } @Override @@ -277,12 +274,17 @@ public class SysAuthServiceImpl implements SysAuthService { this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); } + @Override + public UserTypeEnum getUserType() { + return UserTypeEnum.ADMIN; + } + private void createLogoutLog(Long userId, String username) { SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); reqDTO.setTraceId(TracerUtils.getTraceId()); reqDTO.setUserId(userId); - reqDTO.setUserType(USER_TYPE_ENUM.getValue()); + reqDTO.setUserType(getUserType().getValue()); reqDTO.setUsername(username); reqDTO.setUserAgent(ServletUtils.getUserAgent()); reqDTO.setUserIp(ServletUtils.getClientIP()); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java index d5b2ad1..98ca016 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java @@ -23,6 +23,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -47,7 +48,7 @@ public class SysUserServiceImpl implements SysUserService { @Value("${sys.user.init-password:yudaoyuanma}") private String userInitPassword; - @Resource + @Resource(name = "sysUserMapper") // userMapper 存在重名 private SysUserMapper userMapper; @Resource diff --git a/yudao-admin-server/src/main/resources/application-local.yaml b/yudao-admin-server/src/main/resources/application-local.yaml index 9932671..411f2a6 100644 --- a/yudao-admin-server/src/main/resources/application-local.yaml +++ b/yudao-admin-server/src/main/resources/application-local.yaml @@ -174,6 +174,18 @@ logging: cn.iocoder.yudao.coreservice.modules.system.dal.mysql: debug cn.iocoder.yudao.coreservice.modules.tool.dal.mysql: debug +--- #################### 微信公众号相关配置 #################### +wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 + mp: + # 公众号配置(必填) + app-id: wx041349c6f39b268b + secret: 5abee519483bc9f8cb37ce280e814bd0 + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + --- #################### 芋道相关配置 #################### # 芋道配置项,设置当前项目所有自定义的配置 diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml index 7652dd5..09bbc33 100644 --- a/yudao-admin-server/src/main/resources/application.yaml +++ b/yudao-admin-server/src/main/resources/application.yaml @@ -48,11 +48,17 @@ yudao: info: version: 1.0.0 base-package: cn.iocoder.yudao.adminserver + member-package: cn.iocoder.yudao.module.member core-service: base-package: cn.iocoder.yudao.coreservice web: - api-prefix: /api - controller-package: ${yudao.info.base-package} + admin-api: + prefix: /api + controller: ${yudao.info.base-package} + app-api: + prefix: /app-api + controller: cn.iocoder.yudao.module.member.controller.app + swagger: title: 管理后台 description: 提供管理员管理的所有功能 @@ -72,7 +78,13 @@ yudao: - cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants tenant: # 多租户相关配置项 tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置 - url: + url: ## TODO 芋艿:迁移到 web 配置项下, admin-ui: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + sms-code: # 短信验证码相关的配置项 + expire-times: 10m + send-frequency: 1m + send-maximum-quantity-per-day: 10 + begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 + end-code: 9999 # 这里配置 9999 的原因是,测试方便。 debug: false diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java index a594bce..8ba8b57 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO; */ public interface InfFileCoreService { - /** * 保存文件,并返回文件的访问路径 * diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsCoreServiceImpl.java index 3893ba3..787d2a1 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsCoreServiceImpl.java @@ -2,8 +2,6 @@ package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.coreservice.modules.member.service.user.MbrUserCoreService; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage; @@ -43,8 +41,6 @@ public class SysSmsCoreServiceImpl implements SysSmsCoreService { @Resource private SysUserCoreService sysUserCoreService; @Resource - private MbrUserCoreService mbrUserCoreService; - @Resource private SysSmsTemplateCoreService smsTemplateCoreService; @Resource private SysSmsLogCoreService smsLogCoreService; @@ -72,10 +68,11 @@ public class SysSmsCoreServiceImpl implements SysSmsCoreService { public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map templateParams) { // 如果 mobile 为空,则加载用户编号对应的手机号 if (StrUtil.isEmpty(mobile)) { - MbrUserDO user = mbrUserCoreService.getUser(userId); - if (user != null) { - mobile = user.getMobile(); - } +// MbrUserDO user = mbrUserCoreService.getUser(userId); +// if (user != null) { +// mobile = user.getMobile(); +// } + // TODO 芋艿:重构 } // 执行发送 return this.sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java index b03fc58..d589ac7 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java @@ -15,7 +15,8 @@ import org.springframework.context.annotation.Configuration; * @author 芋道源码 */ @Configuration -@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"}, annotationClass = Mapper.class, +@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}", "${yudao.info.member-package}"}, + annotationClass = Mapper.class, lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试 public class YudaoMybatisAutoConfiguration { diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java index 684cfed..ae8b124 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -7,6 +7,9 @@ import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthServiceImpl; +import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -20,6 +23,7 @@ import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import javax.annotation.Resource; +import java.util.List; /** * Spring Security 自动配置类,主要用于相关组件的配置 @@ -29,7 +33,7 @@ import javax.annotation.Resource; * * @author 芋道源码 */ -@Configuration +@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(SecurityProperties.class) public class YudaoSecurityAutoConfiguration { @@ -64,8 +68,8 @@ public class YudaoSecurityAutoConfiguration { * 退出处理类 Bean */ @Bean - public LogoutSuccessHandler logoutSuccessHandler(SecurityAuthFrameworkService securityFrameworkService) { - return new LogoutSuccessHandlerImpl(securityProperties, securityFrameworkService); + public LogoutSuccessHandler logoutSuccessHandler(SecurityAuthService securityAuthService) { + return new LogoutSuccessHandlerImpl(securityProperties, securityAuthService); } /** @@ -83,9 +87,18 @@ public class YudaoSecurityAutoConfiguration { * Token 认证过滤器 Bean */ @Bean - public JWTAuthenticationTokenFilter authenticationTokenFilter(SecurityAuthFrameworkService securityFrameworkService, + public JWTAuthenticationTokenFilter authenticationTokenFilter(SecurityAuthService securityAuthService, GlobalExceptionHandler globalExceptionHandler) { - return new JWTAuthenticationTokenFilter(securityProperties, securityFrameworkService, globalExceptionHandler); + return new JWTAuthenticationTokenFilter(securityProperties, securityAuthService, globalExceptionHandler); + } + + /** + * 安全认证的 Service Bean + */ + @Bean + public SecurityAuthService securityAuthService(List securityFrameworkServices, + WebProperties webProperties) { + return new SecurityAuthServiceImpl(securityFrameworkServices, webProperties); } /** diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java index a0f1c87..a00b2c2 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -65,13 +65,15 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap */ @Resource private JWTAuthenticationTokenFilter authenticationTokenFilter; + /** * 自定义的权限映射 Bean * * @see #configure(HttpSecurity) */ @Resource - private Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer; + private Customizer.ExpressionInterceptUrlRegistry> + authorizeRequestsCustomizer; /** * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 @@ -89,8 +91,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService) - .passwordEncoder(passwordEncoder); + auth + .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); } /** @@ -123,16 +125,16 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap // 一堆自定义的 Spring Security 处理器 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) .accessDeniedHandler(accessDeniedHandler).and() - .logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出 + .logout().logoutUrl(buildAdminApi("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出 // 设置每个请求的权限 ①:全局共享规则 httpSecurity.authorizeRequests() // 登录的接口,可匿名访问 - .antMatchers(api("/login")).anonymous() + .antMatchers(buildAdminApi("/login")).anonymous() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() // 文件的获取接口,可匿名访问 - .antMatchers(api("/infra/file/get/**")).anonymous() + .antMatchers(buildAdminApi("/infra/file/get/**")).anonymous() // Swagger 接口文档 .antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-resources/**").anonymous() @@ -143,11 +145,11 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap .antMatchers("/actuator/**").anonymous() // Druid 监控 TODO 芋艿:等对接了 druid admin 后,在调整下。 .antMatchers("/druid/**").anonymous() - // oAuth2 auth2/login/gitee - .antMatchers(api("/auth2/login/**")).anonymous() - .antMatchers(api("/auth2/authorization/**")).anonymous() + // oAuth2 auth2/login/gitee TODO 芋艿:貌似可以删除 + .antMatchers(buildAdminApi("/auth2/login/**")).anonymous() + .antMatchers(buildAdminApi("/auth2/authorization/**")).anonymous() .antMatchers("/api/callback/**").anonymous() - // 设置每个请求的权限 ②:每个项目的自定义规则 + // 设置每个请求的权限 ②:每个项目的自定义规则 TODO 芋艿:改造成多个,方便每个模块自定义规则 .and().authorizeRequests(authorizeRequestsCustomizer) // 设置每个请求的权限 ③:兜底规则,必须认证 .authorizeRequests().anyRequest().authenticated() @@ -156,8 +158,14 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } - private String api(String url) { - return webProperties.getApiPrefix() + url; + private String buildAdminApi(String url) { + // TODO 芋艿:多模块 + return webProperties.getAdminApi().getPrefix() + url; + } + + private String buildAppApi(String url) { + // TODO 芋艿:多模块 + return webProperties.getAppApi().getPrefix() + url; } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java index c83318b..61685e9 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java @@ -2,17 +2,15 @@ package cn.iocoder.yudao.framework.security.core.filter; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.security.config.SecurityProperties; import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import lombok.AllArgsConstructor; -import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; -import javax.annotation.Resource; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -30,7 +28,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { private final SecurityProperties securityProperties; - private final SecurityAuthFrameworkService authService; + private final SecurityAuthService authService; private final GlobalExceptionHandler globalExceptionHandler; @@ -42,10 +40,10 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { if (StrUtil.isNotEmpty(token)) { try { // 验证 token 有效性 - LoginUser loginUser = authService.verifyTokenAndRefresh(token); + LoginUser loginUser = authService.verifyTokenAndRefresh(request, token); // 模拟 Login 功能,方便日常开发调试 if (loginUser == null) { - loginUser = this.mockLoginUser(token); + loginUser = this.mockLoginUser(request, token); } // 设置当前用户 if (loginUser != null) { @@ -67,10 +65,11 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { * * 注意,在线上环境下,一定要关闭该功能!!! * + * @param request 请求 * @param token 模拟的 token,格式为 {@link SecurityProperties#getTokenSecret()} + 用户编号 * @return 模拟的 LoginUser */ - private LoginUser mockLoginUser(String token) { + private LoginUser mockLoginUser(HttpServletRequest request, String token) { if (!securityProperties.getMockEnable()) { return null; } @@ -79,7 +78,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { return null; } Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length())); - return authService.mockLogin(userId); + return authService.mockLogin(request, userId); } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java index 1bf8091..e61b351 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java @@ -2,16 +2,14 @@ package cn.iocoder.yudao.framework.security.core.handler; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.security.config.SecurityProperties; -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import lombok.AllArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import org.springframework.stereotype.Component; -import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -26,14 +24,14 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { private final SecurityProperties securityProperties; - private final SecurityAuthFrameworkService securityFrameworkService; + private final SecurityAuthService authService; @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { // 执行退出 String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); if (StrUtil.isNotBlank(token)) { - securityFrameworkService.logout(token); + authService.logout(request, token); } // 返回成功 ServletUtils.writeJSON(response, CommonResult.success(null)); 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 28c8f6d..1f76e16 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 @@ -1,10 +1,11 @@ package cn.iocoder.yudao.framework.security.core.service; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.security.core.LoginUser; import org.springframework.security.core.userdetails.UserDetailsService; /** - * Security 框架 Auth Service 接口,定义 security 组件需要的功能 + * Security 框架 Auth Service 接口,定义不同用户类型的 {@link UserTypeEnum} 需要实现的方法 * * @author 芋道源码 */ @@ -34,4 +35,11 @@ public interface SecurityAuthFrameworkService extends UserDetailsService { */ void logout(String token); + /** + * 获得用户类型。每个用户类型,对应一个 SecurityAuthFrameworkService 实现类。 + * + * @return 用户类型 + */ + UserTypeEnum getUserType(); + } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java new file mode 100644 index 0000000..4fee9cd --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.security.core.service; + +import cn.iocoder.yudao.framework.security.core.LoginUser; + +import javax.servlet.http.HttpServletRequest; + +/** + * 安全认证的 Service 接口,对 security 组件提供统一的 Auth 相关的方法。 + * 主要是会基于 {@link HttpServletRequest} 参数,匹配对应的 {@link SecurityAuthFrameworkService} 实现,然后调用其方法。 + * 因此,在方法的定义上,和 {@link SecurityAuthFrameworkService} 差不多。 + * + * @author 芋道源码 + */ +public interface SecurityAuthService { + + /** + * 校验 token 的有效性,并获取用户信息 + * 通过后,刷新 token 的过期时间 + * + * @param request 请求 + * @param token token + * @return 用户信息 + */ + LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token); + + /** + * 模拟指定用户编号的 LoginUser + * + * @param request 请求 + * @param userId 用户编号 + * @return 登录用户 + */ + LoginUser mockLogin(HttpServletRequest request, Long userId); + + /** + * 基于 token 退出登录 + * + * @param request 请求 + * @param token token + */ + void logout(HttpServletRequest request, String token); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java new file mode 100644 index 0000000..d9ab8eb --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.security.core.service; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.web.config.WebProperties; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 安全认证的 Service 实现类,基于请求地址,计算到对应的 {@link UserTypeEnum} 枚举,从而拿到对应的 {@link SecurityAuthFrameworkService} 实现 + * + * @author 芋道源码 + */ +public class SecurityAuthServiceImpl implements SecurityAuthService { + + private final Map services = new HashMap<>(); + private final WebProperties properties; + + public SecurityAuthServiceImpl(List serviceList, WebProperties properties) { + serviceList.forEach(service -> services.put(service.getUserType(), service)); + this.properties = properties; + } + + @Override + public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) { + return selectService(request).verifyTokenAndRefresh(token); + } + + @Override + public LoginUser mockLogin(HttpServletRequest request, Long userId) { + return selectService(request).mockLogin(userId); + } + + @Override + public void logout(HttpServletRequest request, String token) { + selectService(request).logout(token); + } + + private SecurityAuthFrameworkService selectService(HttpServletRequest request) { + // 第一步,获得用户类型 + UserTypeEnum userType = getUserType(request); + // 第二步,获得 SecurityAuthFrameworkService + SecurityAuthFrameworkService service = services.get(userType); + Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", + request.getRequestURI(), userType); + return service; + } + + private UserTypeEnum getUserType(HttpServletRequest request) { + if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) { + return UserTypeEnum.ADMIN; + } + if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) { + return UserTypeEnum.MEMBER; + } + throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI())); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java index 57133c8..3295e34 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.apilog.core.filter; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.ServletUtil; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -25,6 +26,8 @@ import java.io.IOException; import java.util.Date; import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.*; + /** * API 访问日志 Filter * @@ -42,7 +45,8 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { @Override protected boolean shouldNotFilter(HttpServletRequest request) { // 只过滤 API 请求的地址 - return !request.getRequestURI().startsWith(webProperties.getApiPrefix()); + return !StrUtil.startWithAny(request.getRequestURI(), webProperties.getAppApi().getPrefix(), + webProperties.getAppApi().getPrefix()); } @Override @@ -73,7 +77,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex); apiAccessLogFrameworkService.createApiAccessLogAsync(accessLog); } catch (Throwable th) { - log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), JsonUtils.toJsonString(accessLog), th); + log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th); } } @@ -99,7 +103,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { accessLog.setApplicationName(applicationName); accessLog.setRequestUrl(request.getRequestURI()); Map requestParams = MapUtil.builder().put("query", queryString).put("body", requestBody).build(); - accessLog.setRequestParams(JsonUtils.toJsonString(requestParams)); + accessLog.setRequestParams(toJsonString(requestParams)); accessLog.setRequestMethod(request.getMethod()); accessLog.setUserAgent(ServletUtils.getUserAgent(request)); accessLog.setUserIp(ServletUtil.getClientIP(request)); diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java index 2edc3e8..23a4aff 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java @@ -5,6 +5,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @ConfigurationProperties(prefix = "yudao.web") @@ -12,26 +14,37 @@ import javax.validation.constraints.NotNull; @Data public class WebProperties { - /** - * API 前缀,实现所有 Controller 提供的 RESTFul API 的统一前缀 - * - * - * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题 - * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。 - * - * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer) - */ - @NotNull(message = "API 前缀不能为空") - private String apiPrefix; - - /** - * Controller 所在包 - * - * 主要目的是,给该 Controller 设置指定的 {@link #apiPrefix} - * - * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级 - */ - @NotNull(message = "Controller 所在包不能为空") - private String controllerPackage; + @NotNull(message = "APP API 不能为空") + private Api appApi; + @NotNull(message = "Admin API 不能为空") + private Api adminApi; + + @Data + @Valid + public static class Api { + + /** + * API 前缀,实现所有 Controller 提供的 RESTFul API 的统一前缀 + * + * + * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题 + * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。 + * + * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer) + */ + @NotEmpty(message = "API 前缀不能为空") + private String prefix; + + /** + * Controller 所在包 + * + * 主要目的是,给该 Controller 设置指定的 {@link #prefix} + * + * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级 + */ + @NotEmpty(message = "Controller 所在包不能为空") + private String controller; + + } } 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 5d390cd..c3bcb20 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 @@ -38,10 +38,19 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { - // 设置 API 前缀,仅仅匹配 controller 包下的 - configurer.addPathPrefix(webProperties.getApiPrefix(), clazz -> - clazz.isAnnotationPresent(RestController.class) - && clazz.getPackage().getName().startsWith(webProperties.getControllerPackage())); // 仅仅匹配 controller 包 + configurePathMatch(configurer, webProperties.getAdminApi()); + configurePathMatch(configurer, webProperties.getAppApi()); + } + + /** + * 设置 API 前缀,仅仅匹配 controller 包下的 + * + * @param configurer 配置 + * @param api API 配置 + */ + private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) { + configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class) + && clazz.getPackage().getName().startsWith(api.getController())); // 仅仅匹配 controller 包 } @Bean diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java deleted file mode 100644 index 3ac616a..0000000 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.member.api.user; - -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; - -/** - * 会员用户的 API 接口 - * - * @author 芋道源码 - */ -public interface MemberUserApi { - - /** - * 获得会员用户信息 - * - * @param id 用户编号 - * @return 用户信息 - */ - MemberUserRespDTO getMemberUser(Long id); - -} diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java new file mode 100644 index 0000000..ba742a2 --- /dev/null +++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.api.user; + +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; + +/** + * 会员用户的 API 接口 + * + * @author 芋道源码 + */ +public interface UserApi { + + /** + * 获得会员用户信息 + * + * @param id 用户编号 + * @return 用户信息 + */ + UserRespDTO getUser(Long id); + +} diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java deleted file mode 100644 index 82eec95..0000000 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.member.api.user.dto; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; - -/** - * 用户信息 Response DTO - * - * @author 芋道源码 - */ -public class MemberUserRespDTO { - - /** - * 用户ID - */ - private Long id; - /** - * 用户昵称 - */ - private String nickname; - /** - * 帐号状态 - * - * 枚举 {@link CommonStatusEnum} - */ - private Integer status; - - /** - * 手机 - */ - private String mobile; - -} diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java new file mode 100644 index 0000000..ef2ecde --- /dev/null +++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.member.api.user.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; + +/** + * 用户信息 Response DTO + * + * @author 芋道源码 + */ +public class UserRespDTO { + + /** + * 用户ID + */ + private Long id; + /** + * 用户昵称 + */ + private String nickname; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 手机 + */ + private String mobile; + +} diff --git a/yudao-module-member/yudao-module-member-impl/pom.xml b/yudao-module-member/yudao-module-member-impl/pom.xml index d4b064f..de46508 100644 --- a/yudao-module-member/yudao-module-member-impl/pom.xml +++ b/yudao-module-member/yudao-module-member-impl/pom.xml @@ -18,16 +18,18 @@ - cn.iocoder.boot - yudao-core-service + yudao-module-member-api + ${revision} + cn.iocoder.boot - yudao-spring-boot-starter-biz-dict + yudao-core-service + cn.iocoder.boot yudao-spring-boot-starter-biz-sms @@ -40,11 +42,6 @@ cn.iocoder.boot - yudao-spring-boot-starter-web - - - - cn.iocoder.boot yudao-spring-boot-starter-security @@ -59,32 +56,12 @@ yudao-spring-boot-starter-redis - - - cn.iocoder.boot - yudao-spring-boot-starter-config - - - - cn.iocoder.boot yudao-spring-boot-starter-mq - - - cn.iocoder.boot - yudao-spring-boot-starter-protection - - - - - cn.iocoder.boot - yudao-spring-boot-starter-monitor - - cn.iocoder.boot diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java new file mode 100644 index 0000000..5f97979 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.api; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java new file mode 100644 index 0000000..656642e --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.member.api.user; + +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; +import cn.iocoder.yudao.module.member.convert.user.UserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.service.user.UserService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 会员用户的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class UserApiImpl implements UserApi { + + @Resource + private UserService userService; + + @Override + public UserRespDTO getUser(Long id) { + UserDO user = userService.getUser(id); + return UserConvert.INSTANCE.convert2(user); + } + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java new file mode 100644 index 0000000..652bbb6 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.controller.admin.address; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java new file mode 100644 index 0000000..23b3c23 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.controller.admin.user; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java new file mode 100644 index 0000000..c8c1021 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.controller.app.address; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java index 76437eb..3876e70 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.service.auth.AuthService; +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -31,7 +31,8 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti public class AppAuthController { @Resource - private SysAuthService authService; + private AuthService authService; + @Resource private SysSmsCodeService smsCodeService; @Resource @@ -55,7 +56,7 @@ public class AppAuthController { @PostMapping("/send-sms-code") @ApiOperation(value = "发送手机验证码") - public CommonResult sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { + public CommonResult sendSmsCode(@RequestBody @Valid AppAuthSendSmsReqVO reqVO) { smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); return success(true); } diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java index 64cc22a..6d33b18 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -15,6 +15,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; +// TODO 芋艿:code review 相关逻辑 @ApiModel("APP 端 - 校验验证码 Request VO") @Data @NoArgsConstructor @@ -37,4 +38,5 @@ public class AppAuthCheckCodeReqVO { @NotNull(message = "发送场景不能为空") @InEnum(SysSmsSceneEnum.class) private Integer scene; + } diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java index 5ae291f..9f48ee6 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java @@ -13,6 +13,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; +// TODO 芋艿:code review 相关逻辑 @ApiModel("APP 端 - 重置密码 Request VO") @Data @NoArgsConstructor diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java new file mode 100644 index 0000000..9e53351 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +@ApiModel("APP 端 - 发送手机验证码 Response VO") +@Data +@Accessors(chain = true) +public class AppAuthSendSmsReqVO { + + @ApiModelProperty(value = "手机号", example = "15601691234") + @Mobile + private String mobile; + + @ApiModelProperty(value = "发送场景", example = "1", notes = "对应 MbrSmsSceneEnum 枚举") + @NotNull(message = "发送场景不能为空") + @InEnum(SysSmsSceneEnum.class) + private Integer scene; + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java index cbbd17f..4bbecbc 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java @@ -11,6 +11,7 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; +// TODO 芋艿:code review 相关逻辑 @ApiModel("APP 端 - 修改密码 Request VO") @Data @NoArgsConstructor diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppSendSmsReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppSendSmsReqVO.java deleted file mode 100644 index 7a7620d..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppSendSmsReqVO.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.member.controller.app.auth.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotNull; - -@ApiModel("APP 端 - 发送手机验证码 Response VO") -@Data -@Accessors(chain = true) -public class AppSendSmsReqVO { - - @ApiModelProperty(value = "手机号", example = "15601691234") - @Mobile - private String mobile; - - @ApiModelProperty(value = "发送场景", example = "1", notes = "对应 MbrSmsSceneEnum 枚举") - @NotNull(message = "发送场景不能为空") - @InEnum(SysSmsSceneEnum.class) - private Integer scene; - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java index 758eb7b..cf5b534 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java @@ -1,13 +1,12 @@ package cn.iocoder.yudao.module.member.controller.app.user; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; +import cn.iocoder.yudao.module.member.convert.user.UserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.service.user.UserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -17,13 +16,12 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.validation.Valid; - import java.io.IOException; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY; +import static cn.iocoder.yudao.module.member.enums.MemberErrorCodeConstants.FILE_IS_EMPTY; @Api(tags = "APP 端 - 用户个人中心") @RestController @@ -33,39 +31,40 @@ import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConst public class AppUserController { @Resource - private MbrUserService userService; + private UserService userService; @PutMapping("/update-nickname") @ApiOperation("修改用户昵称") @PreAuthenticated - public CommonResult updateNickname(@RequestParam("nickname") String nickname) { - userService.updateNickname(getLoginUserId(), nickname); + public CommonResult updateUserNickname(@RequestParam("nickname") String nickname) { + userService.updateUserNickname(getLoginUserId(), nickname); return success(true); } @PutMapping("/update-avatar") @ApiOperation("修改用户头像") @PreAuthenticated - public CommonResult updateAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException { + public CommonResult updateUserAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException { if (file.isEmpty()) { - throw ServiceExceptionUtil.exception(MbrErrorCodeConstants.FILE_IS_EMPTY); + throw exception(FILE_IS_EMPTY); } - String avatar = userService.updateAvatar(getLoginUserId(), file.getInputStream()); + String avatar = userService.updateUserAvatar(getLoginUserId(), file.getInputStream()); return success(avatar); } @GetMapping("/get") @ApiOperation("获得基本信息") @PreAuthenticated - public CommonResult getUserInfo() { - return success(userService.getUserInfo(getLoginUserId())); + public CommonResult getUserInfo() { + UserDO user = userService.getUser(getLoginUserId()); + return success(UserConvert.INSTANCE.convert(user)); } @PostMapping("/update-mobile") @ApiOperation(value = "修改用户手机") @PreAuthenticated - public CommonResult updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) { - userService.updateMobile(getLoginUserId(), reqVO); + public CommonResult updateMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) { + userService.updateUserMobile(getLoginUserId(), reqVO); return success(true); } diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java index fe91566..ded94ef 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java @@ -38,6 +38,8 @@ public class AppUserUpdateMobileReqVO { @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") private String oldCode; + // TODO @芋艿:oldMobile 应该不用传递 + @ApiModelProperty(value = "原手机号",required = true,example = "15823654487") @NotBlank(message = "手机号不能为空") @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java new file mode 100644 index 0000000..419a70e --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.member.convert.auth; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface AuthConvert { + + AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); + + @Mapping(source = "mobile", target = "username") + LoginUser convert0(UserDO bean); + + default LoginUser convert(UserDO bean) { + // 目的,为了设置 UserTypeEnum.MEMBER.getValue() + return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue()); + } + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/SysAuthConvert.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/SysAuthConvert.java deleted file mode 100644 index df9a353..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/SysAuthConvert.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.member.convert.auth; - -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - -@Mapper -public interface SysAuthConvert { - - SysAuthConvert INSTANCE = Mappers.getMapper(SysAuthConvert.class); - - @Mapping(source = "mobile", target = "username") - LoginUser convert0(MbrUserDO bean); - - default LoginUser convert(MbrUserDO bean) { - // 目的,为了设置 UserTypeEnum.MEMBER.getValue() - return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue()); - } - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java index 139b6ef..a490edf 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.member.convert.user; -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -9,6 +11,7 @@ public interface UserConvert { UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); - AppUserInfoRespVO convert(MemberUserDO bean); + AppUserInfoRespVO convert(UserDO bean); + UserRespDTO convert2(UserDO bean); } diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java deleted file mode 100644 index 0b77f4e..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.iocoder.yudao.module.member.dal.dataobject.user; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -import java.util.Date; - -/** - * 会员中心的用户 DO - * - * uk_mobile 索引:基于 {@link #mobile} 字段 - * - * @author 芋道源码 - */ -@TableName(value = "member_user", autoResultMap = true) -@Data -@EqualsAndHashCode(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MemberUserDO extends TenantBaseDO { - - /** - * 用户ID - */ - @TableId - private Long id; - /** - * 用户昵称 - */ - private String nickname; - /** - * 用户头像 - */ - private String avatar; - /** - * 帐号状态 - * - * 枚举 {@link CommonStatusEnum} - */ - private Integer status; - - /** - * 手机 - */ - private String mobile; - /** - * 加密后的密码 - * - * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐 - */ - private String password; - /** - * 注册 IP - */ - private String registerIp; - /** - * 最后登录IP - */ - private String loginIp; - /** - * 最后登录时间 - */ - private Date loginDate; - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java new file mode 100644 index 0000000..f451680 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.user; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import java.util.Date; + +/** + * 会员用户 DO + * + * uk_mobile 索引:基于 {@link #mobile} 字段 + * + * @author 芋道源码 + */ +@TableName(value = "mbr_user", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserDO extends TenantBaseDO { + + /** + * 用户ID + */ + @TableId + private Long id; + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户头像 + */ + private String avatar; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 手机 + */ + private String mobile; + /** + * 加密后的密码 + * + * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐 + */ + private String password; + /** + * 注册 IP + */ + private String registerIp; + /** + * 最后登录IP + */ + private String loginIp; + /** + * 最后登录时间 + */ + private Date loginDate; + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java index 8007911..ccdbcf6 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java @@ -3,10 +3,9 @@ package cn.iocoder.yudao.module.member.dal.mysql.sms; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO; -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; import org.apache.ibatis.annotations.Mapper; -// TODO @芋艿: +// TODO @芋艿:拿到 system 模块下 @Mapper public interface SysSmsCodeMapper extends BaseMapperX { diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MbrUserMapper.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MbrUserMapper.java deleted file mode 100644 index 49b6a9f..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MbrUserMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.member.dal.mysql.user; - -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import org.apache.ibatis.annotations.Mapper; - -/** - * MbrUserDO Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface MbrUserMapper extends BaseMapperX { - - default MbrUserDO selectByMobile(String mobile) { - return selectOne(MbrUserDO::getMobile, mobile); - } - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java new file mode 100644 index 0000000..d962811 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.dal.mysql.user; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 会员 User Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface UserMapper extends BaseMapperX { + + default UserDO selectByMobile(String mobile) { + return selectOne(UserDO::getMobile, mobile); + } + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java index 06c6545..5b05c46 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java @@ -3,5 +3,7 @@ * 1. data object:数据对象 * 2. redis:Redis 的 CRUD 操作 * 3. mysql:MySQL 的 CRUD 操作 + * + * 其中,MySQL 的表以 mbr_ 作为前缀 */ package cn.iocoder.yudao.module.member.dal; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java index f5d6e64..8dfa9fb 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java @@ -1 +1,4 @@ +/** + * 占位,后续有类后,可以删除,避免 package 无法提交到 Git 上 + */ package cn.iocoder.yudao.module.member.dal.redis; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/security/SecurityConfiguration.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/security/SecurityConfiguration.java deleted file mode 100644 index 32368f8..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/security/SecurityConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.member.framework.security; - -import cn.iocoder.yudao.framework.web.config.WebProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.Customizer; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; - -import javax.annotation.Resource; - -@Configuration -public class SecurityConfiguration { - - @Resource - private WebProperties webProperties; - - @Bean - public Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() { - return registry -> { - registry.antMatchers(api("/**")).permitAll(); // 默认 API 都是用户可访问 - }; - } - - private String api(String url) { - return webProperties.getApiPrefix() + url; - } - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java new file mode 100644 index 0000000..98b87c5 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.member.service.auth; + +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; + +import javax.validation.Valid; + +/** + * 会员的认证 Service 接口 + * + * 提供用户的账号密码登录、token 的校验等认证相关的功能 + * + * @author 芋道源码 + */ +public interface AuthService extends SecurityAuthFrameworkService { + + /** + * 手机 + 密码登录 + * + * @param reqVO 登录信息 + * @param userIp 用户 IP + * @param userAgent 用户 UA + * @return 身份令牌,使用 JWT 方式 + */ + String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent); + + /** + * 手机 + 验证码登陆 + * + * @param reqVO 登陆信息 + * @param userIp 用户 IP + * @param userAgent 用户 UA + * @return 身份令牌,使用 JWT 方式 + */ + String smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent); + + + /** + * 社交登录,使用 code 授权码 + * + * @param reqVO 登录信息 + * @param userIp 用户 IP + * @param userAgent 用户 UA + * @return 身份令牌,使用 JWT 方式 + */ + String socialLogin(@Valid AppAuthSocialLoginReqVO reqVO, String userIp, String userAgent); + + /** + * 社交登录,使用 手机号 + 手机验证码 + * + * @param reqVO 登录信息 + * @param userIp 用户 IP + * @param userAgent 用户 UA + * @return 身份令牌,使用 JWT 方式 + */ + String socialLogin2(@Valid AppAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent); + + /** + * 社交绑定,使用 code 授权码 + * + * @param userId 用户编号 + * @param reqVO 绑定信息 + */ + void socialBind(Long userId, @Valid AppAuthSocialBindReqVO reqVO); + + /** + * 修改用户密码 + * @param userId 用户id + * @param userReqVO 用户请求实体类 + */ + void updatePassword(Long userId, AppAuthUpdatePasswordReqVO userReqVO); + + /** + * 忘记密码 + * @param userReqVO 用户请求实体类 + */ + void resetPassword(AppAuthResetPasswordReqVO userReqVO); + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java new file mode 100644 index 0000000..a28b657 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java @@ -0,0 +1,349 @@ +package cn.iocoder.yudao.module.member.service.auth; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO; +import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum; +import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum; +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; +import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; +import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO; +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.service.user.UserService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants.*; + +/** + * 会员的认证 Service 接口 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class AuthServiceImpl implements AuthService { + + @Resource + @Lazy // 延迟加载,因为存在相互依赖的问题 + private AuthenticationManager authenticationManager; + + @Resource + private UserService userService; + @Resource + private SysSmsCodeService smsCodeService; + @Resource + private SysLoginLogCoreService loginLogCoreService; + @Resource + private SysUserSessionCoreService userSessionCoreService; + @Resource + private SysSocialCoreService socialService; + + @Resource + private PasswordEncoder passwordEncoder; + @Resource + private UserMapper userMapper; + + @Override + public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException { + // 获取 username 对应的 SysUserDO + UserDO user = userService.getUserByMobile(mobile); + if (user == null) { + throw new UsernameNotFoundException(mobile); + } + // 创建 LoginUser 对象 + return AuthConvert.INSTANCE.convert(user); + } + + @Override + public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) { + // 使用手机 + 密码,进行登录。 + LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword()); + + // 缓存登录用户到 Redis 中,返回 sessionId 编号 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); + } + + @Override + @Transactional + public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { + // 校验验证码 + smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(), + reqVO.getCode(), userIp); + + // 获得获得注册用户 + UserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); + Assert.notNull(user, "获取用户失败,结果为空"); + + // 执行登陆 + this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS); + LoginUser loginUser = AuthConvert.INSTANCE.convert(user); + + // 缓存登录用户到 Redis 中,返回 sessionId 编号 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); + } + + @Override + public String socialLogin(AppAuthSocialLoginReqVO reqVO, String userIp, String userAgent) { + // 使用 code 授权码,进行登录 + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); + org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); + + // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错 + String unionId = socialService.getAuthUserUnionId(authUser); + List socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType()); + if (CollUtil.isEmpty(socialUsers)) { + throw exception(AUTH_THIRD_LOGIN_NOT_BIND); + } + + // 自动登录 + UserDO user = userService.getUser(socialUsers.get(0).getUserId()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS); + + // 创建 LoginUser 对象 + LoginUser loginUser = AuthConvert.INSTANCE.convert(user); + + // 绑定社交用户(更新) + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType()); + + // 缓存登录用户到 Redis 中,返回 sessionId 编号 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); + } + + @Override + public String socialLogin2(AppAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) { + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); + org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); + + // 使用手机号、手机验证码登录 + AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder() + .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build(); + String sessionId = this.smsLogin(loginReqVO, userIp, userAgent); + LoginUser loginUser = userSessionCoreService.getLoginUser(sessionId); + + // 绑定社交用户(新增) + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType()); + return sessionId; + } + + @Override + public void socialBind(Long userId, AppAuthSocialBindReqVO reqVO) { + // 使用 code 授权码,进行登录 + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); + org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); + + // 绑定社交用户(新增) + socialService.bindSocialUser(userId, reqVO.getType(), authUser, getUserType()); + } + + private LoginUser login0(String username, String password) { + final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME; + // 用户验证 + Authentication authentication; + try { + // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 + // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 + authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); + } catch (BadCredentialsException badCredentialsException) { + this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } catch (DisabledException disabledException) { + this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.USER_DISABLED); + throw exception(AUTH_LOGIN_USER_DISABLED); + } catch (AuthenticationException authenticationException) { + log.error("[login0][username({}) 发生未知异常]", username, authenticationException); + this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.UNKNOWN_ERROR); + throw exception(AUTH_LOGIN_FAIL_UNKNOWN); + } + // 登录成功的日志 + Assert.notNull(authentication.getPrincipal(), "Principal 不会为空"); + this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.SUCCESS); + return (LoginUser) authentication.getPrincipal(); + } + + private void createLoginLog(String mobile, SysLoginLogTypeEnum logTypeEnum, SysLoginResultEnum loginResult) { + // 获得用户 + UserDO user = userService.getUserByMobile(mobile); + // 插入登录日志 + SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); + reqDTO.setLogType(logTypeEnum.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + if (user != null) { + reqDTO.setUserId(user.getId()); + } + reqDTO.setUsername(mobile); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(loginResult.getResult()); + loginLogCoreService.createLoginLog(reqDTO); + // 更新最后登录时间 + if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { + userService.updateUserLogin(user.getId(), getClientIP()); + } + } + + @Override + public LoginUser verifyTokenAndRefresh(String token) { + // 获得 LoginUser + LoginUser loginUser = userSessionCoreService.getLoginUser(token); + if (loginUser == null) { + return null; + } + // 刷新 LoginUser 缓存 + this.refreshLoginUserCache(token, loginUser); + return loginUser; + } + + private void refreshLoginUserCache(String token, LoginUser loginUser) { + // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 + if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < + userSessionCoreService.getSessionTimeoutMillis() / 3) { + return; + } + + // 重新加载 UserDO 信息 + UserDO user = userService.getUser(loginUser.getId()); + if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { + // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 + throw exception(AUTH_TOKEN_EXPIRED); + } + + // 刷新 LoginUser 缓存 + userSessionCoreService.refreshUserSession(token, loginUser); + } + + @Override + public LoginUser mockLogin(Long userId) { + // 获取用户编号对应的 UserDO + UserDO user = userService.getUser(userId); + if (user == null) { + throw new UsernameNotFoundException(String.valueOf(userId)); + } + + // 执行登陆 + this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); + + // 创建 LoginUser 对象 + return AuthConvert.INSTANCE.convert(user); + } + + @Override + public void logout(String token) { + // 查询用户信息 + LoginUser loginUser = userSessionCoreService.getLoginUser(token); + if (loginUser == null) { + return; + } + // 删除 session + userSessionCoreService.deleteUserSession(token); + // 记录登出日志 + this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); + } + + @Override + public UserTypeEnum getUserType() { + return UserTypeEnum.MEMBER; + } + + @Override + public void updatePassword(Long userId, AppAuthUpdatePasswordReqVO reqVO) { + // 检验旧密码 + UserDO userDO = checkOldPassword(userId, reqVO.getOldPassword()); + + // 更新用户密码 + UserDO mbrUserDO = UserDO.builder().id(userDO.getId()) + .password(passwordEncoder.encode(reqVO.getPassword())).build(); + userMapper.updateById(mbrUserDO); + } + + @Override + public void resetPassword(AppAuthResetPasswordReqVO reqVO) { + // 检验用户是否存在 + UserDO userDO = checkUserIfExists(reqVO.getMobile()); + + // 使用验证码 + smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(), + getClientIP()); + + // 更新密码 + UserDO mbrUserDO = UserDO.builder().build(); + mbrUserDO.setId(userDO.getId()); + mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); + userMapper.updateById(mbrUserDO); + } + + /** + * 校验旧密码 + * + * @param id 用户 id + * @param oldPassword 旧密码 + * @return MemberUserDO 用户实体 + */ + @VisibleForTesting + public UserDO checkOldPassword(Long id, String oldPassword) { + UserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + // 参数:未加密密码,编码后的密码 + if (!passwordEncoder.matches(oldPassword,user.getPassword())) { + throw exception(USER_PASSWORD_FAILED); + } + return user; + } + + public UserDO checkUserIfExists(String mobile) { + UserDO user = userMapper.selectByMobile(mobile); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + + private void createLogoutLog(Long userId, String username) { + SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); + reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(username); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); + loginLogCoreService.createLoginLog(reqDTO); + } + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthService.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthService.java deleted file mode 100644 index a864e1e..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthService.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.iocoder.yudao.module.member.service.auth; - -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; -import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; - -import javax.validation.Valid; - -/** - * 用户前台的认证 Service 接口 - * - * 提供用户的账号密码登录、token 的校验等认证相关的功能 - * - * @author 芋道源码 - */ -public interface SysAuthService extends SecurityAuthFrameworkService { - - /** - * 手机 + 密码登录 - * - * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 - */ - String login(@Valid SysAuthLoginReqVO reqVO, String userIp, String userAgent); - - /** - * 手机 + 验证码登陆 - * - * @param reqVO 登陆信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 - */ - String smsLogin(@Valid SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent); - - - /** - * 社交登录,使用 code 授权码 - * - * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 - */ - String socialLogin(@Valid MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent); - - /** - * 社交登录,使用 手机号 + 手机验证码 - * - * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 - */ - String socialLogin2(@Valid MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent); - - /** - * 社交绑定,使用 code 授权码 - * - * @param userId 用户编号 - * @param reqVO 绑定信息 - */ - void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO); - - /** - * 修改用户密码 - * @param userId 用户id - * @param userReqVO 用户请求实体类 - */ - void updatePassword(Long userId,MbrAuthUpdatePasswordReqVO userReqVO); - - /** - * 忘记密码 - * @param userReqVO 用户请求实体类 - */ - void resetPassword(MbrAuthResetPasswordReqVO userReqVO); -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceImpl.java deleted file mode 100644 index fd68cff..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceImpl.java +++ /dev/null @@ -1,356 +0,0 @@ -package cn.iocoder.yudao.module.member.service.auth; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO; -import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum; -import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum; -import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; -import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; -import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO; -import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; -import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; -import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; -import com.google.common.annotations.VisibleForTesting; -import lombok.extern.slf4j.Slf4j; -import me.zhyd.oauth.model.AuthUser; -import org.springframework.context.annotation.Lazy; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.DisabledException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.List; -import java.util.Objects; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; -import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; - -/** - * Auth Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Slf4j -public class SysAuthServiceImpl implements SysAuthService { - - private static final UserTypeEnum USER_TYPE_ENUM = UserTypeEnum.MEMBER; - - @Resource - @Lazy // 延迟加载,因为存在相互依赖的问题 - private AuthenticationManager authenticationManager; - - @Resource - private MbrUserService userService; - @Resource - private SysSmsCodeService smsCodeService; - @Resource - private SysLoginLogCoreService loginLogCoreService; - @Resource - private SysUserSessionCoreService userSessionCoreService; - @Resource - private SysSocialCoreService socialService; - - @Resource - private StringRedisTemplate stringRedisTemplate; - @Resource - private PasswordEncoder passwordEncoder; - @Resource - private MbrUserMapper userMapper; - - private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER; - - @Override - public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException { - // 获取 username 对应的 SysUserDO - MbrUserDO user = userService.getUserByMobile(mobile); - if (user == null) { - throw new UsernameNotFoundException(mobile); - } - // 创建 LoginUser 对象 - return SysAuthConvert.INSTANCE.convert(user); - } - - @Override - public String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent) { - // 使用手机 + 密码,进行登录。 - LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword()); - - // 缓存登录用户到 Redis 中,返回 sessionId 编号 - return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); - } - - @Override - @Transactional - public String smsLogin(SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { - // 校验验证码 - smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(), - reqVO.getCode(), userIp); - - // 获得获得注册用户 - MbrUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); - Assert.notNull(user, "获取用户失败,结果为空"); - - // 执行登陆 - this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS); - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); - - // 缓存登录用户到 Redis 中,返回 sessionId 编号 - return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); - } - - @Override - public String socialLogin(MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent) { - // 使用 code 授权码,进行登录 - AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); - org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); - - // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错 - String unionId = socialService.getAuthUserUnionId(authUser); - List socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, USER_TYPE_ENUM); - if (CollUtil.isEmpty(socialUsers)) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND); - } - - // 自动登录 - MbrUserDO user = userService.getUser(socialUsers.get(0).getUserId()); - if (user == null) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_NOT_EXISTS); - } - this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS); - - // 创建 LoginUser 对象 - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); - - // 绑定社交用户(更新) - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM); - - // 缓存登录用户到 Redis 中,返回 sessionId 编号 - return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); - } - - @Override - public String socialLogin2(MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) { - AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); - org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); - - // 使用手机号、手机验证码登录 - SysAuthSmsLoginReqVO loginReqVO = SysAuthSmsLoginReqVO - .builder() - .mobile(reqVO.getMobile()) - .code(reqVO.getSmsCode()) - .build(); - String sessionId = this.smsLogin(loginReqVO, userIp, userAgent); - LoginUser loginUser = userSessionCoreService.getLoginUser(sessionId); - - // 绑定社交用户(新增) - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM); - return sessionId; - } - - @Override - public void socialBind(Long userId, MbrAuthSocialBindReqVO reqVO) { - // 使用 code 授权码,进行登录 - AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); - org.springframework.util.Assert.notNull(authUser, "授权用户不为空"); - - // 绑定社交用户(新增) - socialService.bindSocialUser(userId, reqVO.getType(), authUser, USER_TYPE_ENUM); - } - - private LoginUser login0(String username, String password) { - final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME; - // 用户验证 - Authentication authentication; - try { - // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 - // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 - authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); - } catch (BadCredentialsException badCredentialsException) { - this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS); - } catch (DisabledException disabledException) { - this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.USER_DISABLED); - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.AUTH_LOGIN_USER_DISABLED); - } catch (AuthenticationException authenticationException) { - log.error("[login0][username({}) 发生未知异常]", username, authenticationException); - this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.UNKNOWN_ERROR); - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.AUTH_LOGIN_FAIL_UNKNOWN); - } - // 登录成功的日志 - Assert.notNull(authentication.getPrincipal(), "Principal 不会为空"); - this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.SUCCESS); - return (LoginUser) authentication.getPrincipal(); - } - - private void createLoginLog(String mobile, SysLoginLogTypeEnum logTypeEnum, SysLoginResultEnum loginResult) { - // 获得用户 - MbrUserDO user = userService.getUserByMobile(mobile); - // 插入登录日志 - SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); - reqDTO.setLogType(logTypeEnum.getType()); - reqDTO.setTraceId(TracerUtils.getTraceId()); - if (user != null) { - reqDTO.setUserId(user.getId()); - } - reqDTO.setUsername(mobile); - reqDTO.setUserAgent(ServletUtils.getUserAgent()); - reqDTO.setUserIp(getClientIP()); - reqDTO.setResult(loginResult.getResult()); - loginLogCoreService.createLoginLog(reqDTO); - // 更新最后登录时间 - if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { - userService.updateUserLogin(user.getId(), getClientIP()); - } - } - - @Override - public LoginUser verifyTokenAndRefresh(String token) { - // 获得 LoginUser - LoginUser loginUser = userSessionCoreService.getLoginUser(token); - if (loginUser == null) { - return null; - } - // 刷新 LoginUser 缓存 - this.refreshLoginUserCache(token, loginUser); - return loginUser; - } - - private void refreshLoginUserCache(String token, LoginUser loginUser) { - // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 - if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < - userSessionCoreService.getSessionTimeoutMillis() / 3) { - return; - } - - // 重新加载 MbrUserDO 信息 - MbrUserDO user = userService.getUser(loginUser.getId()); - if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 - } - - // 刷新 LoginUser 缓存 - userSessionCoreService.refreshUserSession(token, loginUser); - } - - @Override - public LoginUser mockLogin(Long userId) { - // 获取用户编号对应的 MbrUserDO - MbrUserDO user = userService.getUser(userId); - if (user == null) { - throw new UsernameNotFoundException(String.valueOf(userId)); - } - - // 执行登陆 - this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); - - // 创建 LoginUser 对象 - return SysAuthConvert.INSTANCE.convert(user); - } - - @Override - public void logout(String token) { - // 查询用户信息 - LoginUser loginUser = userSessionCoreService.getLoginUser(token); - if (loginUser == null) { - return; - } - // 删除 session - userSessionCoreService.deleteUserSession(token); - // 记录登出日志 - this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); - } - - @Override - public void updatePassword(Long userId,MbrAuthUpdatePasswordReqVO reqVO) { - // 检验旧密码 - MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword()); - - // 更新用户密码 - MbrUserDO mbrUserDO = MbrUserDO.builder().build(); - mbrUserDO.setId(userDO.getId()); - mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); - userMapper.updateById(mbrUserDO); - } - - @Override - public void resetPassword(MbrAuthResetPasswordReqVO reqVO) { - // 检验用户是否存在 - MbrUserDO userDO = checkUserIfExists(reqVO.getMobile()); - - // 使用验证码 - smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(),reqVO.getCode(),getClientIP()); - - // 更新密码 - MbrUserDO mbrUserDO = MbrUserDO.builder().build(); - mbrUserDO.setId(userDO.getId()); - mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); - userMapper.updateById(mbrUserDO); - } - - /** - * 校验旧密码 - * - * @param id 用户 id - * @param oldPassword 旧密码 - * @return MbrUserDO 用户实体 - */ - @VisibleForTesting - public MbrUserDO checkOldPassword(Long id, String oldPassword) { - MbrUserDO user = userMapper.selectById(id); - if (user == null) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_NOT_EXISTS); - } - // 参数:未加密密码,编码后的密码 - if (!passwordEncoder.matches(oldPassword,user.getPassword())) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_PASSWORD_FAILED); - } - return user; - } - - public MbrUserDO checkUserIfExists(String mobile) { - MbrUserDO user = userMapper.selectByMobile(mobile); - if (user == null) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_NOT_EXISTS); - } - return user; - } - - - private void createLogoutLog(Long userId, String username) { - SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); - reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); - reqDTO.setTraceId(TracerUtils.getTraceId()); - reqDTO.setUserId(userId); - reqDTO.setUserType(USER_TYPE_ENUM.getValue()); - reqDTO.setUsername(username); - reqDTO.setUserAgent(ServletUtils.getUserAgent()); - reqDTO.setUserIp(getClientIP()); - reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); - loginLogCoreService.createLoginLog(reqDTO); - } - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/package-info.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/package-info.java deleted file mode 100644 index 6223e6e..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.member.service; diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java index 8f0eaf6..e06e9a2 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.member.service.sms; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; /** * 短信验证码 Service 接口 @@ -40,7 +40,6 @@ public interface SysSmsCodeService { */ void sendSmsCodeLogin(Long userId); - /** * 检查验证码是否有效 * @param mobile 手机 diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java index 43b7a17..4104965 100644 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java @@ -1,15 +1,14 @@ package cn.iocoder.yudao.module.member.service.sms; import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; -import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; -import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.dal.mysql.sms.SysSmsCodeMapper; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.framework.sms.SmsCodeProperties; +import cn.iocoder.yudao.module.member.service.user.UserService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -17,9 +16,8 @@ import javax.annotation.Resource; import java.util.Date; import static cn.hutool.core.util.RandomUtil.randomInt; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; -import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; +import static cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants.*; /** * 短信验证码 Service 实现类 @@ -37,7 +35,7 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { private SysSmsCodeMapper smsCodeMapper; @Resource - private MbrUserService mbrUserService; + private UserService userService; @Resource private SysSmsCoreService smsCoreService; @@ -62,9 +60,9 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { public void checkMobileIsRegister(String mobile, Integer scene) { // 检测手机号是否已被使用 - MbrUserDO userByMobile = mbrUserService.getUserByMobile(mobile); - if (userByMobile != null){ - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_IS_EXISTS); + UserDO user = userService.getUserByMobile(mobile); + if (user != null) { + throw ServiceExceptionUtil.exception(USER_SMS_CODE_IS_EXISTS); } // 发送短信 @@ -76,11 +74,11 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null,null); if (lastSmsCode != null) { if (lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); + throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); } if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime() < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_SEND_TOO_FAST); + throw ServiceExceptionUtil.exception(USER_SMS_CODE_SEND_TOO_FAST); } // TODO 芋艿:提升,每个 IP 每天可发送数量 // TODO 芋艿:提升,每个 IP 每小时可发送数量 @@ -97,13 +95,12 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { @Override public void useSmsCode(String mobile, Integer scene, String code, String usedIp) { - // 检测验证码是否有效 SysSmsCodeDO lastSmsCode = this.checkCodeIsExpired(mobile, code, scene); // 判断验证码是否已被使用 if (Boolean.TRUE.equals(lastSmsCode.getUsed())) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_USED); + throw ServiceExceptionUtil.exception(USER_SMS_CODE_USED); } // 使用验证码 @@ -113,9 +110,9 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { @Override public void sendSmsCodeLogin(Long userId) { - MbrUserDO user = mbrUserService.getUser(userId); + UserDO user = userService.getUser(userId); if (user == null){ - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_NOT_EXISTS); + throw ServiceExceptionUtil.exception(USER_NOT_EXISTS); } // 发送验证码 this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP()); @@ -128,15 +125,13 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { // 若验证码不存在,抛出异常 if (lastSmsCode == null) { - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_NOT_FOUND); + throw ServiceExceptionUtil.exception(USER_SMS_CODE_NOT_FOUND); } if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime() >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期 - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_EXPIRED); + throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXPIRED); } - return lastSmsCode; - } } diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserService.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserService.java deleted file mode 100644 index be02945..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserService.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.iocoder.yudao.module.member.service.user; - -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; - -import java.io.InputStream; - -/** - * 前台用户 Service 接口 - * - * @author 芋道源码 - */ -public interface MbrUserService { - - /** - * 通过手机查询用户 - * - * @param mobile 手机 - * @return 用户对象 - */ - MbrUserDO getUserByMobile(String mobile); - - /** - * 基于手机号创建用户。 - * 如果用户已经存在,则直接进行返回 - * - * @param mobile 手机号 - * @param registerIp 注册 IP - * @return 用户对象 - */ - MbrUserDO createUserIfAbsent(@Mobile String mobile, String registerIp); - - /** - * 更新用户的最后登陆信息 - * - * @param id 用户编号 - * @param loginIp 登陆 IP - */ - void updateUserLogin(Long id, String loginIp); - - /** - * 通过用户 ID 查询用户 - * - * @param id 用户ID - * @return 用户对象信息 - */ - MbrUserDO getUser(Long id); - - /** - * 修改用户昵称 - * @param userId 用户id - * @param nickname 用户新昵称 - */ - void updateNickname(Long userId, String nickname); - - /** - * 修改用户头像 - * @param userId 用户id - * @param inputStream 头像文件 - * @return 头像url - */ - String updateAvatar(Long userId, InputStream inputStream); - - /** - * 根据用户id,获取用户头像与昵称 - * - * @param userId 用户id - * @return 用户响应实体类 - */ - MbrUserInfoRespVO getUserInfo(Long userId); - - /** - * 修改手机 - * @param userId 用户id - * @param reqVO 请求实体 - */ - void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO); - -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImpl.java deleted file mode 100644 index de53135..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImpl.java +++ /dev/null @@ -1,162 +0,0 @@ -package cn.iocoder.yudao.module.member.service.user; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; -import cn.iocoder.yudao.userserver.modules.member.convert.user.UserProfileConvert; -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; -import com.google.common.annotations.VisibleForTesting; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.io.InputStream; -import java.util.Date; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; -import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.USER_NOT_EXISTS; -import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED; - -/** - * User Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Valid -@Slf4j -public class MbrUserServiceImpl implements MbrUserService { - - @Resource - private MbrUserMapper userMapper; - - @Resource - private InfFileCoreService fileCoreService; - - @Resource - private PasswordEncoder passwordEncoder; - - @Resource - private SysSmsCodeService smsCodeService; - - - @Override - public MbrUserDO getUserByMobile(String mobile) { - return userMapper.selectByMobile(mobile); - } - - @Override - public MbrUserDO createUserIfAbsent(String mobile, String registerIp) { - // 用户已经存在 - MbrUserDO user = userMapper.selectByMobile(mobile); - if (user != null) { - return user; - } - // 用户不存在,则进行创建 - return this.createUser(mobile, registerIp); - } - - private MbrUserDO createUser(String mobile, String registerIp) { - // 生成密码 - String password = IdUtil.fastSimpleUUID(); - // 插入用户 - MbrUserDO user = new MbrUserDO(); - user.setMobile(mobile); - user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 - user.setPassword(passwordEncoder.encode(password)); // 加密密码 - user.setRegisterIp(registerIp); - userMapper.insert(user); - return user; - } - - @Override - public void updateUserLogin(Long id, String loginIp) { - userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date())); - } - - @Override - public MbrUserDO getUser(Long id) { - return userMapper.selectById(id); - } - - @Override - public void updateNickname(Long userId, String nickname) { - MbrUserDO user = this.checkUserExists(userId); - // 仅当新昵称不等于旧昵称时进行修改 - if (nickname.equals(user.getNickname())){ - return; - } - MbrUserDO userDO = new MbrUserDO(); - userDO.setId(user.getId()); - userDO.setNickname(nickname); - userMapper.updateById(userDO); - } - - @Override - public String updateAvatar(Long userId, InputStream avatarFile) { - this.checkUserExists(userId); - // 创建文件 - String avatar = fileCoreService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile)); - // 更新头像路径 - MbrUserDO userDO = MbrUserDO.builder() - .id(userId) - .avatar(avatar) - .build(); - userMapper.updateById(userDO); - return avatar; - } - - @Override - public MbrUserInfoRespVO getUserInfo(Long userId) { - MbrUserDO user = this.checkUserExists(userId); - // 拼接返回结果 - return UserProfileConvert.INSTANCE.convert(user); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) { - // 检测用户是否存在 - checkUserExists(userId); - - // 校验旧手机和旧验证码 - SysSmsCodeDO sysSmsCodeDO = smsCodeService.checkCodeIsExpired(reqVO.getOldMobile(), reqVO.getOldCode(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene()); - // 判断旧code是否未被使用,如果是,抛出异常 - if (Boolean.FALSE.equals(sysSmsCodeDO.getUsed())){ - throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED); - } - - // 使用新验证码 - smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP()); - - // 更新用户手机 - MbrUserDO userDO = MbrUserDO.builder().id(userId).mobile(reqVO.getMobile()).build(); - userMapper.updateById(userDO); - } - - @VisibleForTesting - public MbrUserDO checkUserExists(Long id) { - if (id == null) { - return null; - } - MbrUserDO user = userMapper.selectById(id); - if (user == null) { - throw exception(USER_NOT_EXISTS); - }else{ - return user; - } - } -} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java new file mode 100644 index 0000000..454e19d --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.member.service.user; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; + +import java.io.InputStream; + +/** + * 会员用户 Service 接口 + * + * @author 芋道源码 + */ +public interface UserService { + + /** + * 通过手机查询用户 + * + * @param mobile 手机 + * @return 用户对象 + */ + UserDO getUserByMobile(String mobile); + + /** + * 基于手机号创建用户。 + * 如果用户已经存在,则直接进行返回 + * + * @param mobile 手机号 + * @param registerIp 注册 IP + * @return 用户对象 + */ + UserDO createUserIfAbsent(@Mobile String mobile, String registerIp); + + /** + * 更新用户的最后登陆信息 + * + * @param id 用户编号 + * @param loginIp 登陆 IP + */ + void updateUserLogin(Long id, String loginIp); + + /** + * 通过用户 ID 查询用户 + * + * @param id 用户ID + * @return 用户对象信息 + */ + UserDO getUser(Long id); + + /** + * 修改用户昵称 + * @param userId 用户id + * @param nickname 用户新昵称 + */ + void updateUserNickname(Long userId, String nickname); + + /** + * 修改用户头像 + * @param userId 用户id + * @param inputStream 头像文件 + * @return 头像url + */ + String updateUserAvatar(Long userId, InputStream inputStream); + + /** + * 修改手机 + * @param userId 用户id + * @param reqVO 请求实体 + */ + void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO); + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java new file mode 100644 index 0000000..a899b79 --- /dev/null +++ b/yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.member.service.user; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper; +import cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.io.InputStream; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.module.member.enums.MemberErrorCodeConstants.USER_NOT_EXISTS; + +/** + * 会员 User Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Valid +@Slf4j +public class UserServiceImpl implements UserService { + + @Resource + private UserMapper memberUserMapper; + + @Resource + private InfFileCoreService fileCoreService; + @Resource + private SysSmsCodeService smsCodeService; + + @Resource + private PasswordEncoder passwordEncoder; + + @Override + public UserDO getUserByMobile(String mobile) { + return memberUserMapper.selectByMobile(mobile); + } + + @Override + public UserDO createUserIfAbsent(String mobile, String registerIp) { + // 用户已经存在 + UserDO user = memberUserMapper.selectByMobile(mobile); + if (user != null) { + return user; + } + // 用户不存在,则进行创建 + return this.createUser(mobile, registerIp); + } + + private UserDO createUser(String mobile, String registerIp) { + // 生成密码 + String password = IdUtil.fastSimpleUUID(); + // 插入用户 + UserDO user = new UserDO(); + user.setMobile(mobile); + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 + user.setPassword(passwordEncoder.encode(password)); // 加密密码 + user.setRegisterIp(registerIp); + memberUserMapper.insert(user); + return user; + } + + @Override + public void updateUserLogin(Long id, String loginIp) { + memberUserMapper.updateById(new UserDO().setId(id) + .setLoginIp(loginIp).setLoginDate(new Date())); + } + + @Override + public UserDO getUser(Long id) { + return memberUserMapper.selectById(id); + } + + @Override + public void updateUserNickname(Long userId, String nickname) { + UserDO user = this.checkUserExists(userId); + // 仅当新昵称不等于旧昵称时进行修改 + if (nickname.equals(user.getNickname())){ + return; + } + UserDO userDO = new UserDO(); + userDO.setId(user.getId()); + userDO.setNickname(nickname); + memberUserMapper.updateById(userDO); + } + + @Override + public String updateUserAvatar(Long userId, InputStream avatarFile) { + this.checkUserExists(userId); + // 创建文件 + String avatar = fileCoreService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile)); + // 更新头像路径 + memberUserMapper.updateById(UserDO.builder().id(userId).avatar(avatar).build()); + return avatar; + } + + @Transactional(rollbackFor = Exception.class) + public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) { + // 检测用户是否存在 + checkUserExists(userId); + + // 校验旧手机和旧验证码 + SysSmsCodeDO sysSmsCodeDO = smsCodeService.checkCodeIsExpired(reqVO.getOldMobile(), reqVO.getOldCode(), + SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene()); + // 判断旧 code 是否未被使用,如果是,抛出异常 + if (Boolean.FALSE.equals(sysSmsCodeDO.getUsed())){ + throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED); + } + + // 使用新验证码 + smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), + reqVO.getCode(),getClientIP()); + + // 更新用户手机 + memberUserMapper.updateById(UserDO.builder().id(userId).mobile(reqVO.getMobile()).build()); + } + + @VisibleForTesting + public UserDO checkUserExists(Long id) { + if (id == null) { + return null; + } + UserDO user = memberUserMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + +} diff --git a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java index ff1c8a7..aa38ab9 100644 --- a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java +++ b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java @@ -1,20 +1,18 @@ package cn.iocoder.yudao.module.member.service.auth; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; -import cn.iocoder.yudao.module.member.controller.app.auth.vo.MbrAuthResetPasswordReqVO; -import cn.iocoder.yudao.module.member.controller.app.auth.vo.MbrAuthUpdatePasswordReqVO; -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; -import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthResetPasswordReqVO; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswordReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper; +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.service.user.UserService; +import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -34,17 +32,17 @@ import static org.mockito.Mockito.when; // TODO @芋艿:单测的 review,等逻辑都达成一致后 /** - * {@link SysAuthService} 的单元测试类 + * {@link AuthService} 的单元测试类 * * @author 宋天 */ -@Import({SysAuthServiceImpl.class, YudaoRedisAutoConfiguration.class}) +@Import({AuthServiceImpl.class, YudaoRedisAutoConfiguration.class}) public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { @MockBean private AuthenticationManager authenticationManager; @MockBean - private MbrUserService userService; + private UserService userService; @MockBean private SysSmsCodeService smsCodeService; @MockBean @@ -58,21 +56,21 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { @MockBean private PasswordEncoder passwordEncoder; @Resource - private MbrUserMapper mbrUserMapper; + private UserMapper mbrUserMapper; @Resource - private SysAuthServiceImpl authService; + private AuthServiceImpl authService; @Test public void testUpdatePassword_success(){ // 准备参数 - MbrUserDO userDO = randomMbrUserDO(); + UserDO userDO = randomUserDO(); mbrUserMapper.insert(userDO); // 新密码 String newPassword = randomString(); // 请求实体 - MbrAuthUpdatePasswordReqVO reqVO = MbrAuthUpdatePasswordReqVO.builder() + AppAuthUpdatePasswordReqVO reqVO = AppAuthUpdatePasswordReqVO.builder() .oldPassword(userDO.getPassword()) .password(newPassword) .build(); @@ -83,14 +81,14 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { when(passwordEncoder.encode(newPassword)).thenReturn(newPassword); // 更新用户密码 - authService.updatePassword(userDO.getId(),reqVO); + authService.updatePassword(userDO.getId(), reqVO); assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),newPassword); } @Test public void testResetPassword_success(){ // 准备参数 - MbrUserDO userDO = randomMbrUserDO(); + UserDO userDO = randomUserDO(); mbrUserMapper.insert(userDO); // 随机密码 @@ -102,7 +100,7 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { when(passwordEncoder.encode(password)).thenReturn(password); // 更新用户密码 - MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO(); + AppAuthResetPasswordReqVO reqVO = new AppAuthResetPasswordReqVO(); reqVO.setMobile(userDO.getMobile()); reqVO.setPassword(password); reqVO.setCode(code); @@ -115,12 +113,12 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { // ========== 随机对象 ========== @SafeVarargs - private static MbrUserDO randomMbrUserDO(Consumer... consumers) { - Consumer consumer = (o) -> { + private static UserDO randomUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 o.setPassword(randomString()); }; - return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers)); + return randomPojo(UserDO.class, ArrayUtils.append(consumer, consumers)); } diff --git a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/package-info.java b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/package-info.java deleted file mode 100644 index 6223e6e..0000000 --- a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.member.service; diff --git a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java index ecd728e..96c562f 100644 --- a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java +++ b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java @@ -2,18 +2,17 @@ package cn.iocoder.yudao.module.member.service.user; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; -import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; -import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper; +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum; +import cn.iocoder.yudao.module.member.service.auth.AuthServiceImpl; +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; +import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -27,30 +26,29 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; -import static cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; // TODO @芋艿:单测的 review,等逻辑都达成一致后 /** - * {@link MbrUserServiceImpl} 的单元测试类 + * {@link UserServiceImpl} 的单元测试类 * * @author 宋天 */ -@Import({MbrUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) +@Import({UserServiceImpl.class, YudaoRedisAutoConfiguration.class}) public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { @Resource - private MbrUserServiceImpl mbrUserService; + private UserServiceImpl mbrUserService; @Resource private StringRedisTemplate stringRedisTemplate; @Resource - private MbrUserMapper userMapper; + private UserMapper userMapper; @MockBean - private SysAuthServiceImpl authService; + private AuthServiceImpl authService; @MockBean private InfFileCoreService fileCoreService; @@ -64,14 +62,14 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { @Test public void testUpdateNickName_success(){ // mock 数据 - MbrUserDO userDO = randomMbrUserDO(); + UserDO userDO = randomUserDO(); userMapper.insert(userDO); // 随机昵称 String newNickName = randomString(); // 调用接口修改昵称 - mbrUserService.updateNickname(userDO.getId(),newNickName); + mbrUserService.updateUserNickname(userDO.getId(),newNickName); // 查询新修改后的昵称 String nickname = mbrUserService.getUser(userDO.getId()).getNickname(); // 断言 @@ -79,20 +77,9 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { } @Test - public void testGetUserInfo_success(){ - // mock 数据 - MbrUserDO userDO = randomMbrUserDO(); - userMapper.insert(userDO); - - // 查询用户昵称与头像 - MbrUserInfoRespVO userInfo = mbrUserService.getUserInfo(userDO.getId()); - System.out.println(userInfo); - } - - @Test public void testUpdateAvatar_success(){ // mock 数据 - MbrUserDO dbUser = randomMbrUserDO(); + UserDO dbUser = randomUserDO(); userMapper.insert(dbUser); // 准备参数 @@ -103,7 +90,7 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { String avatar = randomString(); when(fileCoreService.createFile(anyString(), eq(avatarFileBytes))).thenReturn(avatar); // 调用 - String str = mbrUserService.updateAvatar(userId, avatarFile); + String str = mbrUserService.updateUserAvatar(userId, avatarFile); // 断言 assertEquals(avatar, str); } @@ -112,11 +99,10 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { public void updateMobile_success(){ // mock数据 String oldMobile = randomNumbers(11); - MbrUserDO userDO = randomMbrUserDO(); + UserDO userDO = randomUserDO(); userDO.setMobile(oldMobile); userMapper.insert(userDO); - // 旧手机和旧验证码 SysSmsCodeDO codeDO = new SysSmsCodeDO(); String oldCode = RandomUtil.randomString(4); @@ -129,12 +115,12 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { // 更新手机号 String newMobile = randomNumbers(11); String newCode = randomNumbers(4); - MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO(); + AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO(); reqVO.setMobile(newMobile); reqVO.setCode(newCode); reqVO.setOldMobile(oldMobile); reqVO.setOldCode(oldCode); - mbrUserService.updateMobile(userDO.getId(),reqVO); + mbrUserService.updateUserMobile(userDO.getId(),reqVO); assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile); } @@ -142,11 +128,11 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { // ========== 随机对象 ========== @SafeVarargs - private static MbrUserDO randomMbrUserDO(Consumer... consumers) { - Consumer consumer = (o) -> { + private static UserDO randomUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 }; - return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers)); + return randomPojo(UserDO.class, ArrayUtils.append(consumer, consumers)); } } diff --git a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java index 50d19ad..a927849 100644 --- a/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java +++ b/yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.member.test; import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import cn.iocoder.yudao.userserver.config.RedisTestConfiguration; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import org.redisson.spring.starter.RedissonAutoConfiguration; diff --git a/yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml b/yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml index d306a7a..237068e 100644 --- a/yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml +++ b/yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml @@ -42,3 +42,8 @@ mybatis: --- #################### 芋道相关配置 #################### # 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module.member.dal.mysql + core-service: + base-package: cn.iocoder.yudao.module.member.dal.mysql # TODO 芋艿:要清理掉 diff --git a/yudao-user-server/src/main/resources/application-dev.yaml b/yudao-user-server/src/main/resources/application-dev.yaml index 7e6aa35..f44bc49 100644 --- a/yudao-user-server/src/main/resources/application-dev.yaml +++ b/yudao-user-server/src/main/resources/application-dev.yaml @@ -124,6 +124,19 @@ logging: file: name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 微信公众号相关配置 #################### +wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 + mp: + # 公众号配置(必填) + app-id: wx041349c6f39b268b + secret: 5abee519483bc9f8cb37ce280e814bd0 + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + --- #################### 芋道相关配置 #################### # 芋道配置项,设置当前项目所有自定义的配置 diff --git a/yudao-user-server/src/main/resources/application.yaml b/yudao-user-server/src/main/resources/application.yaml index 2095433..1d78923 100644 --- a/yudao-user-server/src/main/resources/application.yaml +++ b/yudao-user-server/src/main/resources/application.yaml @@ -66,11 +66,6 @@ yudao: constants-class-list: - cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants - cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants - sms-code: # 短信验证码相关的配置项 - expire-times: 10m - send-frequency: 1m - send-maximum-quantity-per-day: 10 - begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 - end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + debug: false -- libgit2 0.21.4