Commit 6aca4ae9fd3af1861a33fbdd4d014571fa000f0f

Authored by YunaiV
2 parents 36d01371 e9efff70

Merge branch 'feature/multi-module' of https://gitee.com/zhijiantianya/ruoyi-vue…

…-pro into feature/flowable

 Conflicts:
	pom.xml
	yudao-module-bpm/yudao-module-bpm-activiti/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java
Showing 119 changed files with 1265 additions and 959 deletions

Too many changes.

To preserve performance only 100 of 119 files are displayed.

http-client.env.json
... ... @@ -2,6 +2,10 @@
2 2 "local": {
3 3 "baseUrl": "http://127.0.0.1:48080/api",
4 4 "userServerUrl": "http://127.0.0.1:28080/api",
5   - "token": "test1"
  5 + "token": "test1",
  6 +
  7 + "userApi": "http://127.0.0.1:48080/app-api",
  8 + "userToken": "test1",
  9 + "userTenentId": "1"
6 10 }
7 11 }
... ...
... ... @@ -13,6 +13,7 @@
13 13 <module>yudao-admin-server</module>
14 14 <module>yudao-user-server</module>
15 15 <module>yudao-core-service</module>
  16 + <module>yudao-module-member</module>
16 17 <module>yudao-module-bpm</module>
17 18 </modules>
18 19  
... ... @@ -21,13 +22,14 @@
21 22 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
22 23  
23 24 <properties>
24   - <revision>1.3.0-snapshot</revision>
  25 + <revision>1.4.0-snapshot</revision>
25 26 <!-- Maven 相关 -->
26 27 <java.version>1.8</java.version>
27 28 <maven.compiler.source>${java.version}</maven.compiler.source>
28 29 <maven.compiler.target>${java.version}</maven.compiler.target>
29 30 <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
30 31 <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
  32 + <!-- 看看咋放到 bom 里 -->
31 33 <lombok.version>1.18.20</lombok.version>
32 34 <mapstruct.version>1.4.1.Final</mapstruct.version>
33 35 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
... ... @@ -55,6 +57,7 @@
55 57 <artifactId>maven-surefire-plugin</artifactId>
56 58 <version>${maven-surefire-plugin.version}</version>
57 59 </plugin>
  60 + <!-- TODO 看看咋放到 bom 里 -->
58 61 <plugin>
59 62 <groupId>org.apache.maven.plugins</groupId>
60 63 <artifactId>maven-compiler-plugin</artifactId>
... ...
yudao-admin-server/pom.xml
... ... @@ -13,10 +13,21 @@
13 13 <packaging>jar</packaging>
14 14  
15 15 <name>yudao-admin-server</name>
16   - <description>管理后台 Server,提供其 API 接口</description>
  16 + <description>
  17 + 后端 Server 的主项目,通过引入需要 yudao-module-xxx 的依赖,
  18 + 从而实现提供 RESTful API 给 yudao-ui-admin、yudao-ui-user 等前端项目。
  19 + 本质上来说,它就是个空壳(容器)!
  20 + </description>
17 21 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
18 22  
19 23 <dependencies>
  24 + <!-- TODO 芋艿:多模块 -->
  25 + <dependency>
  26 + <groupId>cn.iocoder.boot</groupId>
  27 + <artifactId>yudao-module-member-impl</artifactId>
  28 + <version>${revision}</version>
  29 + </dependency>
  30 +
20 31 <!-- 业务组件 -->
21 32 <dependency>
22 33 <groupId>cn.iocoder.boot</groupId>
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/AdminServerApplication.java
... ... @@ -4,7 +4,8 @@ import org.springframework.boot.SpringApplication;
4 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 5  
6 6 @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package}
7   -@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"})
  7 +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}",
  8 + "${yudao.info.member-package}"}) // TODO 芋艿:重构
8 9 public class AdminServerApplication {
9 10  
10 11 public static void main(String[] args) {
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java
... ... @@ -23,19 +23,28 @@ public class SecurityConfiguration {
23 23 public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
24 24 return registry -> {
25 25 // 验证码的接口
26   - registry.antMatchers(api("/system/captcha/**")).anonymous();
  26 + registry.antMatchers(buildAdminApi("/system/captcha/**")).anonymous();
27 27 // 获得租户编号的接口
28   - registry.antMatchers(api("/system/tenant/get-id-by-name")).anonymous();
  28 + registry.antMatchers(buildAdminApi("/system/tenant/get-id-by-name")).anonymous();
29 29 // Spring Boot Admin Server 的安全配置
30 30 registry.antMatchers(adminSeverContextPath).anonymous()
31 31 .antMatchers(adminSeverContextPath + "/**").anonymous();
32 32 // 短信回调 API
33   - registry.antMatchers(api("/system/sms/callback/**")).anonymous();
  33 + registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous();
  34 +
  35 + // 设置 App API 无需认证
  36 + registry.antMatchers(buildAppApi("/**")).permitAll();
34 37 };
35 38 }
36 39  
37   - private String api(String url) {
38   - return webProperties.getApiPrefix() + url;
  40 + private String buildAdminApi(String url) {
  41 + // TODO 芋艿:多模块
  42 + return webProperties.getAdminApi().getPrefix() + url;
  43 + }
  44 +
  45 + private String buildAppApi(String url) {
  46 + // TODO 芋艿:多模块
  47 + return webProperties.getAppApi().getPrefix() + url;
39 48 }
40 49  
41 50 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
... ... @@ -26,6 +26,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
26 26 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
27 27 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
28 28 import cn.iocoder.yudao.framework.security.core.LoginUser;
  29 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;
29 30 import lombok.extern.slf4j.Slf4j;
30 31 import me.zhyd.oauth.model.AuthUser;
31 32 import org.springframework.context.annotation.Lazy;
... ... @@ -60,8 +61,6 @@ import static java.util.Collections.singleton;
60 61 @Slf4j
61 62 public class SysAuthServiceImpl implements SysAuthService {
62 63  
63   - private static final UserTypeEnum USER_TYPE_ENUM = UserTypeEnum.ADMIN;
64   -
65 64 @Resource
66 65 @Lazy // 延迟加载,因为存在相互依赖的问题
67 66 private AuthenticationManager authenticationManager;
... ... @@ -83,7 +82,6 @@ public class SysAuthServiceImpl implements SysAuthService {
83 82 @Resource
84 83 private SysSocialCoreService socialService;
85 84  
86   -
87 85 @Override
88 86 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
89 87 // 获取 username 对应的 SysUserDO
... ... @@ -157,7 +155,8 @@ public class SysAuthServiceImpl implements SysAuthService {
157 155 try {
158 156 // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证
159 157 // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
160   - authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
  158 + authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken(
  159 + username, password, getUserType()));
161 160 // org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
162 161 } catch (BadCredentialsException badCredentialsException) {
163 162 this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS);
... ... @@ -216,7 +215,7 @@ public class SysAuthServiceImpl implements SysAuthService {
216 215  
217 216 // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错
218 217 String unionId = socialService.getAuthUserUnionId(authUser);
219   - List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, USER_TYPE_ENUM);
  218 + List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType());
220 219 if (CollUtil.isEmpty(socialUsers)) {
221 220 throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
222 221 }
... ... @@ -232,7 +231,7 @@ public class SysAuthServiceImpl implements SysAuthService {
232 231 LoginUser loginUser = this.buildLoginUser(user);
233 232  
234 233 // 绑定社交用户(更新)
235   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
  234 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
236 235  
237 236 // 缓存登录用户到 Redis 中,返回 sessionId 编号
238 237 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
... ... @@ -248,7 +247,7 @@ public class SysAuthServiceImpl implements SysAuthService {
248 247 LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
249 248  
250 249 // 绑定社交用户(新增)
251   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
  250 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
252 251  
253 252 // 缓存登录用户到 Redis 中,返回 sessionId 编号
254 253 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
... ... @@ -261,7 +260,7 @@ public class SysAuthServiceImpl implements SysAuthService {
261 260 Assert.notNull(authUser, "授权用户不为空");
262 261  
263 262 // 绑定社交用户(新增)
264   - socialService.bindSocialUser(userId, reqVO.getType(), authUser, USER_TYPE_ENUM);
  263 + socialService.bindSocialUser(userId, reqVO.getType(), authUser, getUserType());
265 264 }
266 265  
267 266 @Override
... ... @@ -277,12 +276,17 @@ public class SysAuthServiceImpl implements SysAuthService {
277 276 this.createLogoutLog(loginUser.getId(), loginUser.getUsername());
278 277 }
279 278  
  279 + @Override
  280 + public UserTypeEnum getUserType() {
  281 + return UserTypeEnum.ADMIN;
  282 + }
  283 +
280 284 private void createLogoutLog(Long userId, String username) {
281 285 SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
282 286 reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
283 287 reqDTO.setTraceId(TracerUtils.getTraceId());
284 288 reqDTO.setUserId(userId);
285   - reqDTO.setUserType(USER_TYPE_ENUM.getValue());
  289 + reqDTO.setUserType(getUserType().getValue());
286 290 reqDTO.setUsername(username);
287 291 reqDTO.setUserAgent(ServletUtils.getUserAgent());
288 292 reqDTO.setUserIp(ServletUtils.getClientIP());
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java
... ... @@ -24,6 +24,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
24 24 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
25 25 import com.google.common.annotations.VisibleForTesting;
26 26 import lombok.extern.slf4j.Slf4j;
  27 +import org.springframework.beans.factory.annotation.Autowired;
27 28 import org.springframework.beans.factory.annotation.Value;
28 29 import org.springframework.security.crypto.password.PasswordEncoder;
29 30 import org.springframework.stereotype.Service;
... ... @@ -48,7 +49,7 @@ public class SysUserServiceImpl implements SysUserService {
48 49 @Value("${sys.user.init-password:yudaoyuanma}")
49 50 private String userInitPassword;
50 51  
51   - @Resource
  52 + @Resource(name = "sysUserMapper") // userMapper 存在重名
52 53 private SysUserMapper userMapper;
53 54  
54 55 @Resource
... ...
yudao-admin-server/src/main/resources/application-local.yaml
... ... @@ -55,6 +55,19 @@ spring:
55 55 username: root
56 56 password: 123456
57 57  
  58 + activiti:
  59 + #1.false:默认值,activiti启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常
  60 + #2.true:启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表
  61 + #3.create_drop:启动时自动创建表,关闭时自动删除表
  62 + #4.drop_create:启动时,删除旧表,再创建新表
  63 + database-schema-update: true
  64 + #activiti7默认不生成历史信息表,需手动设置开启
  65 + db-history-used: true
  66 + check-process-definitions: true
  67 + #full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数
  68 + history-level: full
  69 +
  70 +
58 71 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
59 72 redis:
60 73 host: 127.0.0.1 # 地址
... ... @@ -161,6 +174,18 @@ logging:
161 174 cn.iocoder.yudao.coreservice.modules.system.dal.mysql: debug
162 175 cn.iocoder.yudao.coreservice.modules.tool.dal.mysql: debug
163 176  
  177 +--- #################### 微信公众号相关配置 ####################
  178 +wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
  179 + mp:
  180 + # 公众号配置(必填)
  181 + app-id: wx041349c6f39b268b
  182 + secret: 5abee519483bc9f8cb37ce280e814bd0
  183 + # 存储配置,解决 AccessToken 的跨节点的共享
  184 + config-storage:
  185 + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
  186 + key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置
  187 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
  188 +
164 189 --- #################### 芋道相关配置 ####################
165 190  
166 191 # 芋道配置项,设置当前项目所有自定义的配置
... ...
yudao-admin-server/src/main/resources/application.yaml
... ... @@ -48,11 +48,17 @@ yudao:
48 48 info:
49 49 version: 1.0.0
50 50 base-package: cn.iocoder.yudao.adminserver
  51 + member-package: cn.iocoder.yudao.module.member
51 52 core-service:
52 53 base-package: cn.iocoder.yudao.coreservice
53 54 web:
54   - api-prefix: /api
55   - controller-package: ${yudao.info.base-package}
  55 + admin-api:
  56 + prefix: /api
  57 + controller: ${yudao.info.base-package}
  58 + app-api:
  59 + prefix: /app-api
  60 + controller: cn.iocoder.yudao.module.member.controller.app
  61 +
56 62 swagger:
57 63 title: 管理后台
58 64 description: 提供管理员管理的所有功能
... ... @@ -72,7 +78,13 @@ yudao:
72 78 - cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants
73 79 tenant: # 多租户相关配置项
74 80 tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
75   - url:
  81 + url: ## TODO 芋艿:迁移到 web 配置项下,
76 82 admin-ui: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
  83 + sms-code: # 短信验证码相关的配置项
  84 + expire-times: 10m
  85 + send-frequency: 1m
  86 + send-maximum-quantity-per-day: 10
  87 + begin-code: 9999 # 这里配置 9999 的原因是,测试方便。
  88 + end-code: 9999 # 这里配置 9999 的原因是,测试方便。
77 89  
78 90 debug: false
... ...
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;
9 9 */
10 10 public interface InfFileCoreService {
11 11  
12   -
13 12 /**
14 13 * 保存文件,并返回文件的访问路径
15 14 *
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/dal/mysql/user/MbrUserCoreMapper.java deleted
1   -package cn.iocoder.yudao.coreservice.modules.member.dal.mysql.user;
2   -
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4   -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5   -import org.apache.ibatis.annotations.Mapper;
6   -
7   -@Mapper
8   -public interface MbrUserCoreMapper extends BaseMapperX<MbrUserDO> {
9   -
10   -}
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/package-info.java deleted
1   -/**
2   - * member 包下,我们放会员业务.
3   - * 例如说:会员中心等等
4   - *
5   - * 缩写:mbr
6   - */
7   -package cn.iocoder.yudao.coreservice.modules.member;
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/service/user/MbrUserCoreService.java deleted
1   -package cn.iocoder.yudao.coreservice.modules.member.service.user;
2   -
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4   -
5   -/**
6   - * 前台用户 Core Service 接口
7   - *
8   - * @author 芋道源码
9   - */
10   -public interface MbrUserCoreService {
11   - /**
12   - * 通过用户 ID 查询用户
13   - *
14   - * @param id 用户ID
15   - * @return 用户对象信息
16   - */
17   - MbrUserDO getUser(Long id);
18   -
19   -}
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/service/user/impl/MbrUserCoreServiceImpl.java deleted
1   -package cn.iocoder.yudao.coreservice.modules.member.service.user.impl;
2   -
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4   -import cn.iocoder.yudao.coreservice.modules.member.dal.mysql.user.MbrUserCoreMapper;
5   -import cn.iocoder.yudao.coreservice.modules.member.service.user.MbrUserCoreService;
6   -import lombok.extern.slf4j.Slf4j;
7   -import org.springframework.stereotype.Service;
8   -
9   -import javax.annotation.Resource;
10   -
11   -/**
12   - * User Core Service 实现类
13   - *
14   - * @author 芋道源码
15   - */
16   -@Service
17   -@Slf4j
18   -public class MbrUserCoreServiceImpl implements MbrUserCoreService {
19   -
20   - @Resource
21   - private MbrUserCoreMapper userCoreMapper;
22   -
23   - @Override
24   - public MbrUserDO getUser(Long id) {
25   - return userCoreMapper.selectById(id);
26   - }
27   -
28   -}
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;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
5   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
6   -import cn.iocoder.yudao.coreservice.modules.member.service.user.MbrUserCoreService;
7 5 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
8 6 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
9 7 import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
... ... @@ -43,8 +41,6 @@ public class SysSmsCoreServiceImpl implements SysSmsCoreService {
43 41 @Resource
44 42 private SysUserCoreService sysUserCoreService;
45 43 @Resource
46   - private MbrUserCoreService mbrUserCoreService;
47   - @Resource
48 44 private SysSmsTemplateCoreService smsTemplateCoreService;
49 45 @Resource
50 46 private SysSmsLogCoreService smsLogCoreService;
... ... @@ -72,10 +68,11 @@ public class SysSmsCoreServiceImpl implements SysSmsCoreService {
72 68 public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
73 69 // 如果 mobile 为空,则加载用户编号对应的手机号
74 70 if (StrUtil.isEmpty(mobile)) {
75   - MbrUserDO user = mbrUserCoreService.getUser(userId);
76   - if (user != null) {
77   - mobile = user.getMobile();
78   - }
  71 +// MbrUserDO user = mbrUserCoreService.getUser(userId);
  72 +// if (user != null) {
  73 +// mobile = user.getMobile();
  74 +// }
  75 + // TODO 芋艿:重构
79 76 }
80 77 // 执行发送
81 78 return this.sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/tool/package-info.java deleted
1   -/**
2   - * tool 包下,我们放研发工具,提升研发效率与质量。
3   - * 例如说:代码生成器、接口文档等等
4   - *
5   - * 缩写:tool
6   - */
7   -package cn.iocoder.yudao.coreservice.modules.tool;
yudao-dependencies/pom.xml
... ... @@ -14,7 +14,7 @@
14 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15  
16 16 <properties>
17   - <revision>1.3.0-snapshot</revision>
  17 + <revision>1.4.0-snapshot</revision>
18 18 <!-- 统一依赖管理 -->
19 19 <spring.boot.version>2.4.12</spring.boot.version>
20 20 <!-- Web 相关 -->
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/UserTypeEnum.java
1 1 package cn.iocoder.yudao.framework.common.enums;
2 2  
  3 +import cn.hutool.core.lang.Matcher;
  4 +import cn.hutool.core.util.ArrayUtil;
3 5 import lombok.AllArgsConstructor;
4 6 import lombok.Getter;
5 7  
... ... @@ -22,4 +24,8 @@ public enum UserTypeEnum {
22 24 */
23 25 private final String name;
24 26  
  27 + public static UserTypeEnum valueOf(Integer value) {
  28 + return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values());
  29 + }
  30 +
25 31 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java
... ... @@ -149,6 +149,7 @@ public class OperateLogAspect {
149 149  
150 150 private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) {
151 151 operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId());
  152 + operateLogDTO.setUserType(WebFrameworkUtils.getLoginUserType());
152 153 }
153 154  
154 155 private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO,
... ...
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java
... ... @@ -21,6 +21,9 @@ public class OperateLogCreateReqDTO {
21 21 @ApiModelProperty(value = "用户编号", required = true, example = "1024")
22 22 @NotNull(message = "用户编号不能为空")
23 23 private Long userId;
  24 + @ApiModelProperty(value = "用户类型", required = true, example = "1")
  25 + @NotNull(message = "用户类型不能为空")
  26 + private Integer userType;
24 27  
25 28 @ApiModelProperty(value = "操作模块", required = true, example = "订单")
26 29 @NotEmpty(message = "操作模块不能为空")
... ...
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;
15 15 * @author 芋道源码
16 16 */
17 17 @Configuration
18   -@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"}, annotationClass = Mapper.class,
  18 +@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}", "${yudao.info.member-package}"},
  19 + annotationClass = Mapper.class,
19 20 lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
20 21 public class YudaoMybatisAutoConfiguration {
21 22  
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
1 1 package cn.iocoder.yudao.framework.security.config;
2 2  
3 3 import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
  4 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
4 5 import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy;
5 6 import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
6 7 import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
7 8 import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
8 9 import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;
9 10 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
  11 +import cn.iocoder.yudao.framework.web.config.WebProperties;
10 12 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
11 13 import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
12 14 import org.springframework.boot.context.properties.EnableConfigurationProperties;
... ... @@ -20,6 +22,7 @@ import org.springframework.security.web.access.AccessDeniedHandler;
20 22 import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
21 23  
22 24 import javax.annotation.Resource;
  25 +import java.util.List;
23 26  
24 27 /**
25 28 * Spring Security 自动配置类,主要用于相关组件的配置
... ... @@ -29,7 +32,7 @@ import javax.annotation.Resource;
29 32 *
30 33 * @author 芋道源码
31 34 */
32   -@Configuration
  35 +@Configuration(proxyBeanMethods = false)
33 36 @EnableConfigurationProperties(SecurityProperties.class)
34 37 public class YudaoSecurityAutoConfiguration {
35 38  
... ... @@ -64,8 +67,8 @@ public class YudaoSecurityAutoConfiguration {
64 67 * 退出处理类 Bean
65 68 */
66 69 @Bean
67   - public LogoutSuccessHandler logoutSuccessHandler(SecurityAuthFrameworkService securityFrameworkService) {
68   - return new LogoutSuccessHandlerImpl(securityProperties, securityFrameworkService);
  70 + public LogoutSuccessHandler logoutSuccessHandler(MultiUserDetailsAuthenticationProvider authenticationProvider) {
  71 + return new LogoutSuccessHandlerImpl(securityProperties, authenticationProvider);
69 72 }
70 73  
71 74 /**
... ... @@ -83,9 +86,19 @@ public class YudaoSecurityAutoConfiguration {
83 86 * Token 认证过滤器 Bean
84 87 */
85 88 @Bean
86   - public JWTAuthenticationTokenFilter authenticationTokenFilter(SecurityAuthFrameworkService securityFrameworkService,
  89 + public JWTAuthenticationTokenFilter authenticationTokenFilter(MultiUserDetailsAuthenticationProvider authenticationProvider,
87 90 GlobalExceptionHandler globalExceptionHandler) {
88   - return new JWTAuthenticationTokenFilter(securityProperties, securityFrameworkService, globalExceptionHandler);
  91 + return new JWTAuthenticationTokenFilter(securityProperties, authenticationProvider, globalExceptionHandler);
  92 + }
  93 +
  94 + /**
  95 + * 身份验证的 Provider Bean,通过它实现账号 + 密码的认证
  96 + */
  97 + @Bean
  98 + public MultiUserDetailsAuthenticationProvider authenticationProvider(
  99 + List<SecurityAuthFrameworkService> securityFrameworkServices,
  100 + WebProperties webProperties, PasswordEncoder passwordEncoder) {
  101 + return new MultiUserDetailsAuthenticationProvider(securityFrameworkServices, webProperties, passwordEncoder);
89 102 }
90 103  
91 104 /**
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
1 1 package cn.iocoder.yudao.framework.security.config;
2 2  
  3 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
3 4 import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
4 5 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
5 6 import cn.iocoder.yudao.framework.web.config.WebProperties;
... ... @@ -35,16 +36,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
35 36 @Resource
36 37 private WebProperties webProperties;
37 38  
38   - /**
39   - * 自定义用户【认证】逻辑
40   - */
41   - @Resource
42   - private SecurityAuthFrameworkService userDetailsService;
43   - /**
44   - * Spring Security 加密器
45   - */
46 39 @Resource
47   - private PasswordEncoder passwordEncoder;
  40 + private MultiUserDetailsAuthenticationProvider authenticationProvider;
48 41 /**
49 42 * 认证失败处理类 Bean
50 43 */
... ... @@ -65,13 +58,15 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
65 58 */
66 59 @Resource
67 60 private JWTAuthenticationTokenFilter authenticationTokenFilter;
  61 +
68 62 /**
69 63 * 自定义的权限映射 Bean
70 64 *
71 65 * @see #configure(HttpSecurity)
72 66 */
73 67 @Resource
74   - private Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer;
  68 + private Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry>
  69 + authorizeRequestsCustomizer;
75 70  
76 71 /**
77 72 * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入
... ... @@ -89,8 +84,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
89 84 */
90 85 @Override
91 86 protected void configure(AuthenticationManagerBuilder auth) throws Exception {
92   - auth.userDetailsService(userDetailsService)
93   - .passwordEncoder(passwordEncoder);
  87 + auth.authenticationProvider(authenticationProvider);
94 88 }
95 89  
96 90 /**
... ... @@ -123,16 +117,16 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
123 117 // 一堆自定义的 Spring Security 处理器
124 118 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
125 119 .accessDeniedHandler(accessDeniedHandler).and()
126   - .logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出
  120 + .logout().logoutUrl(buildAdminApi("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出
127 121  
128 122 // 设置每个请求的权限 ①:全局共享规则
129 123 httpSecurity.authorizeRequests()
130 124 // 登录的接口,可匿名访问
131   - .antMatchers(api("/login")).anonymous()
  125 + .antMatchers(buildAdminApi("/login")).anonymous()
132 126 // 静态资源,可匿名访问
133 127 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
134 128 // 文件的获取接口,可匿名访问
135   - .antMatchers(api("/infra/file/get/**")).anonymous()
  129 + .antMatchers(buildAdminApi("/infra/file/get/**")).anonymous()
136 130 // Swagger 接口文档
137 131 .antMatchers("/swagger-ui.html").anonymous()
138 132 .antMatchers("/swagger-resources/**").anonymous()
... ... @@ -143,11 +137,11 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
143 137 .antMatchers("/actuator/**").anonymous()
144 138 // Druid 监控 TODO 芋艿:等对接了 druid admin 后,在调整下。
145 139 .antMatchers("/druid/**").anonymous()
146   - // oAuth2 auth2/login/gitee
147   - .antMatchers(api("/auth2/login/**")).anonymous()
148   - .antMatchers(api("/auth2/authorization/**")).anonymous()
  140 + // oAuth2 auth2/login/gitee TODO 芋艿:貌似可以删除
  141 + .antMatchers(buildAdminApi("/auth2/login/**")).anonymous()
  142 + .antMatchers(buildAdminApi("/auth2/authorization/**")).anonymous()
149 143 .antMatchers("/api/callback/**").anonymous()
150   - // 设置每个请求的权限 ②:每个项目的自定义规则
  144 + // 设置每个请求的权限 ②:每个项目的自定义规则 TODO 芋艿:改造成多个,方便每个模块自定义规则
151 145 .and().authorizeRequests(authorizeRequestsCustomizer)
152 146 // 设置每个请求的权限 ③:兜底规则,必须认证
153 147 .authorizeRequests().anyRequest().authenticated()
... ... @@ -156,8 +150,14 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
156 150 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
157 151 }
158 152  
159   - private String api(String url) {
160   - return webProperties.getApiPrefix() + url;
  153 + private String buildAdminApi(String url) {
  154 + // TODO 芋艿:多模块
  155 + return webProperties.getAdminApi().getPrefix() + url;
  156 + }
  157 +
  158 + private String buildAppApi(String url) {
  159 + // TODO 芋艿:多模块
  160 + return webProperties.getAppApi().getPrefix() + url;
161 161 }
162 162  
163 163 }
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.security.core.authentication;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  6 +import cn.iocoder.yudao.framework.security.core.LoginUser;
  7 +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
  8 +import cn.iocoder.yudao.framework.web.config.WebProperties;
  9 +import org.springframework.security.authentication.AuthenticationProvider;
  10 +import org.springframework.security.authentication.BadCredentialsException;
  11 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  12 +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
  13 +import org.springframework.security.core.AuthenticationException;
  14 +import org.springframework.security.core.userdetails.UserDetails;
  15 +import org.springframework.security.crypto.password.PasswordEncoder;
  16 +
  17 +import javax.servlet.http.HttpServletRequest;
  18 +import java.util.HashMap;
  19 +import java.util.List;
  20 +import java.util.Map;
  21 +
  22 +/**
  23 + * 支持多用户类型的 AuthenticationProvider 实现类
  24 + *
  25 + * 为什么不用 {@link org.springframework.security.authentication.ProviderManager} 呢?
  26 + * 原因是,需要每个用户类型实现对应的 {@link AuthenticationProvider} + authentication,略显麻烦。实际,也是可以实现的。
  27 + *
  28 + * 另外,额外支持 verifyTokenAndRefresh 校验令牌、logout 登出、mockLogin 模拟登陆等操作。
  29 + * 实际上,它就是 {@link SecurityAuthFrameworkService} 定义的三个接口。
  30 + * 因为需要支持多种类型,所以需要根据请求的 URL,判断出对应的用户类型,从而使用对应的 SecurityAuthFrameworkService 是吸纳
  31 + *
  32 + * @see cn.iocoder.yudao.framework.common.enums.UserTypeEnum
  33 + * @author 芋道源码
  34 + */
  35 +public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
  36 +
  37 + private final Map<UserTypeEnum, SecurityAuthFrameworkService> services = new HashMap<>();
  38 +
  39 + private final WebProperties properties;
  40 +
  41 + private final PasswordEncoder passwordEncoder;
  42 +
  43 + public MultiUserDetailsAuthenticationProvider(List<SecurityAuthFrameworkService> serviceList,
  44 + WebProperties properties, PasswordEncoder passwordEncoder) {
  45 + serviceList.forEach(service -> services.put(service.getUserType(), service));
  46 + this.properties = properties;
  47 + this.passwordEncoder = passwordEncoder;
  48 + }
  49 +
  50 + // ========== AuthenticationProvider 相关 ==========
  51 +
  52 + @Override
  53 + protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
  54 + throws AuthenticationException {
  55 + // 执行用户的加载
  56 + return selectService(authentication).loadUserByUsername(username);
  57 + }
  58 +
  59 + private SecurityAuthFrameworkService selectService(UsernamePasswordAuthenticationToken authentication) {
  60 + // 第一步,获得用户类型
  61 + UserTypeEnum userType = getUserType(authentication);
  62 + // 第二步,获得 SecurityAuthFrameworkService
  63 + SecurityAuthFrameworkService service = services.get(userType);
  64 + Assert.notNull(service, "用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", userType);
  65 + return service;
  66 + }
  67 +
  68 + private UserTypeEnum getUserType(UsernamePasswordAuthenticationToken authentication) {
  69 + Assert.isInstanceOf(MultiUsernamePasswordAuthenticationToken.class, authentication);
  70 + MultiUsernamePasswordAuthenticationToken multiAuthentication = (MultiUsernamePasswordAuthenticationToken) authentication;
  71 + UserTypeEnum userType = multiAuthentication.getUserType();
  72 + Assert.notNull(userType, "用户类型不能为空");
  73 + return userType;
  74 + }
  75 +
  76 + @Override // copy 自 DaoAuthenticationProvider 的 additionalAuthenticationChecks 方法
  77 + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
  78 + throws AuthenticationException {
  79 + // 校验 credentials
  80 + if (authentication.getCredentials() == null) {
  81 + this.logger.debug("Failed to authenticate since no credentials provided");
  82 + throw new BadCredentialsException(this.messages.getMessage(
  83 + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
  84 + }
  85 + // 校验 password
  86 + String presentedPassword = authentication.getCredentials().toString();
  87 + if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
  88 + this.logger.debug("Failed to authenticate since password does not match stored value");
  89 + throw new BadCredentialsException(this.messages.getMessage(
  90 + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
  91 + }
  92 + }
  93 +
  94 + // ========== SecurityAuthFrameworkService 相关 ==========
  95 +
  96 + /**
  97 + * 校验 token 的有效性,并获取用户信息
  98 + * 通过后,刷新 token 的过期时间
  99 + *
  100 + * @param request 请求
  101 + * @param token token
  102 + * @return 用户信息
  103 + */
  104 + public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) {
  105 + return selectService(request).verifyTokenAndRefresh(token);
  106 + }
  107 +
  108 + /**
  109 + * 模拟指定用户编号的 LoginUser
  110 + *
  111 + * @param request 请求
  112 + * @param userId 用户编号
  113 + * @return 登录用户
  114 + */
  115 + public LoginUser mockLogin(HttpServletRequest request, Long userId) {
  116 + return selectService(request).mockLogin(userId);
  117 + }
  118 +
  119 + /**
  120 + * 基于 token 退出登录
  121 + *
  122 + * @param request 请求
  123 + * @param token token
  124 + */
  125 + public void logout(HttpServletRequest request, String token) {
  126 + selectService(request).logout(token);
  127 + }
  128 +
  129 + private SecurityAuthFrameworkService selectService(HttpServletRequest request) {
  130 + // 第一步,获得用户类型
  131 + UserTypeEnum userType = getUserType(request);
  132 + // 第二步,获得 SecurityAuthFrameworkService
  133 + SecurityAuthFrameworkService service = services.get(userType);
  134 + Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类",
  135 + request.getRequestURI(), userType);
  136 + return service;
  137 + }
  138 +
  139 + private UserTypeEnum getUserType(HttpServletRequest request) {
  140 + if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) {
  141 + return UserTypeEnum.ADMIN;
  142 + }
  143 + if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
  144 + return UserTypeEnum.MEMBER;
  145 + }
  146 + throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI()));
  147 + }
  148 +
  149 +}
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.security.core.authentication;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import lombok.Getter;
  5 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  6 +import org.springframework.security.core.GrantedAuthority;
  7 +
  8 +import java.util.Collection;
  9 +
  10 +/**
  11 + * 支持多用户的 UsernamePasswordAuthenticationToken 实现类
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Getter
  16 +public class MultiUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
  17 +
  18 + /**
  19 + * 用户类型
  20 + */
  21 + private UserTypeEnum userType;
  22 +
  23 + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials) {
  24 + super(principal, credentials);
  25 + }
  26 +
  27 + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials,
  28 + Collection<? extends GrantedAuthority> authorities) {
  29 + super(principal, credentials, authorities);
  30 + }
  31 +
  32 + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, UserTypeEnum userType) {
  33 + super(principal, credentials);
  34 + this.userType = userType;
  35 + }
  36 +
  37 + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials,
  38 + Collection<? extends GrantedAuthority> authorities, UserTypeEnum userType) {
  39 + super(principal, credentials, authorities);
  40 + this.userType = userType;
  41 + }
  42 +
  43 +}
... ...
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;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
5 6 import cn.iocoder.yudao.framework.security.config.SecurityProperties;
6 7 import cn.iocoder.yudao.framework.security.core.LoginUser;
7   -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
  8 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
8 9 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
9 10 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
10   -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
11   -import lombok.AllArgsConstructor;
12   -import org.springframework.stereotype.Component;
  11 +import lombok.RequiredArgsConstructor;
13 12 import org.springframework.web.filter.OncePerRequestFilter;
14 13  
15   -import javax.annotation.Resource;
16 14 import javax.servlet.FilterChain;
17 15 import javax.servlet.ServletException;
18 16 import javax.servlet.http.HttpServletRequest;
... ... @@ -25,12 +23,12 @@ import java.io.IOException;
25 23 *
26 24 * @author 芋道源码
27 25 */
28   -@AllArgsConstructor
  26 +@RequiredArgsConstructor
29 27 public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
30 28  
31 29 private final SecurityProperties securityProperties;
32 30  
33   - private final SecurityAuthFrameworkService authService;
  31 + private final MultiUserDetailsAuthenticationProvider authenticationProvider;
34 32  
35 33 private final GlobalExceptionHandler globalExceptionHandler;
36 34  
... ... @@ -42,10 +40,10 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
42 40 if (StrUtil.isNotEmpty(token)) {
43 41 try {
44 42 // 验证 token 有效性
45   - LoginUser loginUser = authService.verifyTokenAndRefresh(token);
  43 + LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token);
46 44 // 模拟 Login 功能,方便日常开发调试
47 45 if (loginUser == null) {
48   - loginUser = this.mockLoginUser(token);
  46 + loginUser = this.mockLoginUser(request, token);
49 47 }
50 48 // 设置当前用户
51 49 if (loginUser != null) {
... ... @@ -67,10 +65,11 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
67 65 *
68 66 * 注意,在线上环境下,一定要关闭该功能!!!
69 67 *
  68 + * @param request 请求
70 69 * @param token 模拟的 token,格式为 {@link SecurityProperties#getTokenSecret()} + 用户编号
71 70 * @return 模拟的 LoginUser
72 71 */
73   - private LoginUser mockLoginUser(String token) {
  72 + private LoginUser mockLoginUser(HttpServletRequest request, String token) {
74 73 if (!securityProperties.getMockEnable()) {
75 74 return null;
76 75 }
... ... @@ -79,7 +78,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
79 78 return null;
80 79 }
81 80 Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length()));
82   - return authService.mockLogin(userId);
  81 + return authenticationProvider.mockLogin(request, userId);
83 82 }
84 83  
85 84 }
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AbstractSignUpUrlAuthenticationSuccessHandler.java deleted
1   -/*
2   - * MIT License
3   - * Copyright (c) 2020-2029 YongWu zheng (dcenter.top and gitee.com/pcore and github.com/ZeroOrInfinity)
4   - *
5   - * Permission is hereby granted, free of charge, to any person obtaining a copy
6   - * of this software and associated documentation files (the "Software"), to deal
7   - * in the Software without restriction, including without limitation the rights
8   - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9   - * copies of the Software, and to permit persons to whom the Software is
10   - * furnished to do so, subject to the following conditions:
11   - *
12   - * The above copyright notice and this permission notice shall be included in all
13   - * copies or substantial portions of the Software.
14   - *
15   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18   - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20   - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21   - * SOFTWARE.
22   - */
23   -package cn.iocoder.yudao.framework.security.core.handler;
24   -
25   -import org.springframework.security.core.Authentication;
26   -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
27   -import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
28   -import org.springframework.security.web.savedrequest.RequestCache;
29   -
30   -import javax.servlet.ServletException;
31   -import javax.servlet.http.HttpServletRequest;
32   -import javax.servlet.http.HttpServletResponse;
33   -import java.io.IOException;
34   -
35   -/**
36   - * @author weir
37   - */
38   -public class AbstractSignUpUrlAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
39   - private RequestCache requestCache = new HttpSessionRequestCache();
40   -
41   - @Override
42   - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
43   - if (requestCache.getRequest(request, response) != null) {
44   - requestCache.getRequest(request, response);
45   - }
46   - super.onAuthenticationSuccess(request,response,authentication);
47   - }
48   -
49   - @Override
50   - public void setRequestCache(RequestCache requestCache) {
51   - this.requestCache = requestCache;
52   - }
53   -}
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;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
5 6 import cn.iocoder.yudao.framework.security.config.SecurityProperties;
6   -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
  7 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
7 8 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
8   -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
9 9 import lombok.AllArgsConstructor;
10 10 import org.springframework.security.core.Authentication;
11 11 import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
12   -import org.springframework.stereotype.Component;
13 12  
14   -import javax.annotation.Resource;
15 13 import javax.servlet.http.HttpServletRequest;
16 14 import javax.servlet.http.HttpServletResponse;
17 15  
... ... @@ -26,14 +24,14 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
26 24  
27 25 private final SecurityProperties securityProperties;
28 26  
29   - private final SecurityAuthFrameworkService securityFrameworkService;
  27 + private final MultiUserDetailsAuthenticationProvider authenticationProvider;
30 28  
31 29 @Override
32 30 public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
33 31 // 执行退出
34 32 String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
35 33 if (StrUtil.isNotBlank(token)) {
36   - securityFrameworkService.logout(token);
  34 + authenticationProvider.logout(request, token);
37 35 }
38 36 // 返回成功
39 37 ServletUtils.writeJSON(response, CommonResult.success(null));
... ...
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java
1 1 package cn.iocoder.yudao.framework.security.core.service;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 4 import cn.iocoder.yudao.framework.security.core.LoginUser;
4 5 import org.springframework.security.core.userdetails.UserDetailsService;
5 6  
6 7 /**
7   - * Security 框架 Auth Service 接口,定义 security 组件需要的功能
  8 + * Security 框架 Auth Service 接口,定义不同用户类型的 {@link UserTypeEnum} 需要实现的方法
8 9 *
9 10 * @author 芋道源码
10 11 */
... ... @@ -34,4 +35,11 @@ public interface SecurityAuthFrameworkService extends UserDetailsService {
34 35 */
35 36 void logout(String token);
36 37  
  38 + /**
  39 + * 获得用户类型。每个用户类型,对应一个 SecurityAuthFrameworkService 实现类。
  40 + *
  41 + * @return 用户类型
  42 + */
  43 + UserTypeEnum getUserType();
  44 +
37 45 }
... ...
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;
2 2  
3 3 import cn.hutool.core.exceptions.ExceptionUtil;
4 4 import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 6 import cn.hutool.extra.servlet.ServletUtil;
6 7 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
7 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
... ... @@ -25,6 +26,8 @@ import java.io.IOException;
25 26 import java.util.Date;
26 27 import java.util.Map;
27 28  
  29 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.*;
  30 +
28 31 /**
29 32 * API 访问日志 Filter
30 33 *
... ... @@ -42,7 +45,8 @@ public class ApiAccessLogFilter extends OncePerRequestFilter {
42 45 @Override
43 46 protected boolean shouldNotFilter(HttpServletRequest request) {
44 47 // 只过滤 API 请求的地址
45   - return !request.getRequestURI().startsWith(webProperties.getApiPrefix());
  48 + return !StrUtil.startWithAny(request.getRequestURI(), webProperties.getAppApi().getPrefix(),
  49 + webProperties.getAppApi().getPrefix());
46 50 }
47 51  
48 52 @Override
... ... @@ -73,7 +77,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter {
73 77 this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex);
74 78 apiAccessLogFrameworkService.createApiAccessLogAsync(accessLog);
75 79 } catch (Throwable th) {
76   - log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), JsonUtils.toJsonString(accessLog), th);
  80 + log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th);
77 81 }
78 82 }
79 83  
... ... @@ -99,7 +103,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter {
99 103 accessLog.setApplicationName(applicationName);
100 104 accessLog.setRequestUrl(request.getRequestURI());
101 105 Map<String, Object> requestParams = MapUtil.<String, Object>builder().put("query", queryString).put("body", requestBody).build();
102   - accessLog.setRequestParams(JsonUtils.toJsonString(requestParams));
  106 + accessLog.setRequestParams(toJsonString(requestParams));
103 107 accessLog.setRequestMethod(request.getMethod());
104 108 accessLog.setUserAgent(ServletUtils.getUserAgent(request));
105 109 accessLog.setUserIp(ServletUtil.getClientIP(request));
... ...
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;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
7 7  
  8 +import javax.validation.Valid;
  9 +import javax.validation.constraints.NotEmpty;
8 10 import javax.validation.constraints.NotNull;
9 11  
10 12 @ConfigurationProperties(prefix = "yudao.web")
... ... @@ -12,26 +14,37 @@ import javax.validation.constraints.NotNull;
12 14 @Data
13 15 public class WebProperties {
14 16  
15   - /**
16   - * API 前缀,实现所有 Controller 提供的 RESTFul API 的统一前缀
17   - *
18   - *
19   - * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题
20   - * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。
21   - *
22   - * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer)
23   - */
24   - @NotNull(message = "API 前缀不能为空")
25   - private String apiPrefix;
26   -
27   - /**
28   - * Controller 所在包
29   - *
30   - * 主要目的是,给该 Controller 设置指定的 {@link #apiPrefix}
31   - *
32   - * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级
33   - */
34   - @NotNull(message = "Controller 所在包不能为空")
35   - private String controllerPackage;
  17 + @NotNull(message = "APP API 不能为空")
  18 + private Api appApi;
  19 + @NotNull(message = "Admin API 不能为空")
  20 + private Api adminApi;
  21 +
  22 + @Data
  23 + @Valid
  24 + public static class Api {
  25 +
  26 + /**
  27 + * API 前缀,实现所有 Controller 提供的 RESTFul API 的统一前缀
  28 + *
  29 + *
  30 + * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题
  31 + * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。
  32 + *
  33 + * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer)
  34 + */
  35 + @NotEmpty(message = "API 前缀不能为空")
  36 + private String prefix;
  37 +
  38 + /**
  39 + * Controller 所在包
  40 + *
  41 + * 主要目的是,给该 Controller 设置指定的 {@link #prefix}
  42 + *
  43 + * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级
  44 + */
  45 + @NotEmpty(message = "Controller 所在包不能为空")
  46 + private String controller;
  47 +
  48 + }
36 49  
37 50 }
... ...
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 {
38 38  
39 39 @Override
40 40 public void configurePathMatch(PathMatchConfigurer configurer) {
41   - // 设置 API 前缀,仅仅匹配 controller 包下的
42   - configurer.addPathPrefix(webProperties.getApiPrefix(), clazz ->
43   - clazz.isAnnotationPresent(RestController.class)
44   - && clazz.getPackage().getName().startsWith(webProperties.getControllerPackage())); // 仅仅匹配 controller 包
  41 + configurePathMatch(configurer, webProperties.getAdminApi());
  42 + configurePathMatch(configurer, webProperties.getAppApi());
  43 + }
  44 +
  45 + /**
  46 + * 设置 API 前缀,仅仅匹配 controller 包下的
  47 + *
  48 + * @param configurer 配置
  49 + * @param api API 配置
  50 + */
  51 + private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) {
  52 + configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class)
  53 + && clazz.getPackage().getName().startsWith(api.getController())); // 仅仅匹配 controller 包
45 54 }
46 55  
47 56 @Bean
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
... ... @@ -55,6 +55,11 @@ public class WebFrameworkUtils {
55 55 return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
56 56 }
57 57  
  58 + public static Integer getLoginUserType() {
  59 + HttpServletRequest request = getRequest();
  60 + return getLoginUserType(request);
  61 + }
  62 +
58 63 public static Long getLoginUserId() {
59 64 HttpServletRequest request = getRequest();
60 65 return getLoginUserId(request);
... ...
yudao-module-bpm/yudao-module-bpm-activiti/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java
... ... @@ -10,10 +10,17 @@ import cn.iocoder.yudao.coreservice.modules.bpm.api.group.BpmUserGroupServiceApi
10 10 import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysDeptCoreService;
11 11 import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysPermissionCoreService;
12 12 import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
  13 +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
  14 +import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
  15 +import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
  16 +import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  17 +import org.activiti.api.runtime.shared.identity.UserGroupManager;
  18 +import org.activiti.core.common.spring.identity.ActivitiUserGroupManagerImpl;
13 19 import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
14 20 import org.springframework.context.ApplicationEventPublisher;
15 21 import org.springframework.context.annotation.Bean;
16 22 import org.springframework.context.annotation.Configuration;
  23 +import org.springframework.security.core.userdetails.UserDetailsService;
17 24  
18 25 import java.util.Collections;
19 26 import java.util.List;
... ... @@ -27,7 +34,15 @@ import static org.activiti.spring.boot.ProcessEngineAutoConfiguration.BEHAVIOR_F
27 34 public class BpmActivitiConfiguration {
28 35  
29 36 /**
30   - * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类,主要设置各种监听器、用户组管理
  37 + * 空用户组的 Bean
  38 + */
  39 + @Bean
  40 + public UserGroupManager userGroupManager() {
  41 + return new EmptyUserGroupManager();
  42 + }
  43 +
  44 + /**
  45 + * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类,主要设置各种监听器
31 46 */
32 47 @Bean
33 48 public ProcessEngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer(
... ... @@ -35,8 +50,6 @@ public class BpmActivitiConfiguration {
35 50 return configuration -> {
36 51 // 注册监听器,例如说 BpmActivitiEventListener
37 52 configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
38   - // 用户组
39   - configuration.setUserGroupManager(new EmptyUserGroupManager());
40 53 };
41 54 }
42 55  
... ...
yudao-module-member/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <groupId>cn.iocoder.boot</groupId>
  7 + <artifactId>yudao</artifactId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <modules>
  12 + <module>yudao-module-member-api</module>
  13 + <module>yudao-module-member-impl</module>
  14 + </modules>
  15 + <artifactId>yudao-module-member</artifactId>
  16 + <packaging>pom</packaging>
  17 +
  18 + <name>${artifactId}</name>
  19 + <description>
  20 + member 模块,我们放会员业务。
  21 + 例如说:会员中心等等
  22 + </description>
  23 +
  24 +</project>
... ...
yudao-module-member/yudao-module-member-api/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <groupId>cn.iocoder.boot</groupId>
  7 + <artifactId>yudao-module-member</artifactId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <artifactId>yudao-module-member-api</artifactId>
  12 + <packaging>jar</packaging>
  13 +
  14 + <name>${artifactId}</name>
  15 + <description>
  16 + member 模块 API,暴露给其它模块调用
  17 + </description>
  18 +
  19 + <dependencies>
  20 + <dependency>
  21 + <groupId>cn.iocoder.boot</groupId>
  22 + <artifactId>yudao-common</artifactId>
  23 + </dependency>
  24 + </dependencies>
  25 +
  26 +</project>
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/package-info.java renamed to yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java
1 1 /**
2   - * 占位
  2 + * member API 包,定义暴露给其它模块的 API
3 3 */
4   -package cn.iocoder.yudao.userserver.modules.system.controller;
  4 +package cn.iocoder.yudao.module.member.api;
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.api.user;
  2 +
  3 +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
  4 +
  5 +/**
  6 + * 会员用户的 API 接口
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface UserApi {
  11 +
  12 + /**
  13 + * 获得会员用户信息
  14 + *
  15 + * @param id 用户编号
  16 + * @return 用户信息
  17 + */
  18 + UserRespDTO getUser(Long id);
  19 +
  20 +}
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.api.user.dto;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +
  5 +/**
  6 + * 用户信息 Response DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public class UserRespDTO {
  11 +
  12 + /**
  13 + * 用户ID
  14 + */
  15 + private Long id;
  16 + /**
  17 + * 用户昵称
  18 + */
  19 + private String nickname;
  20 + /**
  21 + * 帐号状态
  22 + *
  23 + * 枚举 {@link CommonStatusEnum}
  24 + */
  25 + private Integer status;
  26 +
  27 + /**
  28 + * 手机
  29 + */
  30 + private String mobile;
  31 +
  32 +}
... ...
yudao-module-member/yudao-module-member-impl/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <groupId>cn.iocoder.boot</groupId>
  7 + <artifactId>yudao-module-member</artifactId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <artifactId>yudao-module-member-impl</artifactId>
  12 + <packaging>jar</packaging>
  13 +
  14 + <name>${artifactId}</name>
  15 + <description>
  16 + member 模块,我们放会员业务。
  17 + 例如说:会员中心等等
  18 + </description>
  19 +
  20 + <dependencies>
  21 + <dependency>
  22 + <groupId>cn.iocoder.boot</groupId>
  23 + <artifactId>yudao-module-member-api</artifactId>
  24 + <version>${revision}</version>
  25 + </dependency>
  26 +
  27 + <!-- 业务组件 -->
  28 + <dependency>
  29 + <groupId>cn.iocoder.boot</groupId>
  30 + <artifactId>yudao-core-service</artifactId>
  31 + </dependency>
  32 +
  33 + <dependency>
  34 + <groupId>cn.iocoder.boot</groupId>
  35 + <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>cn.iocoder.boot</groupId>
  39 + <artifactId>yudao-spring-boot-starter-biz-sms</artifactId>
  40 + </dependency>
  41 + <dependency>
  42 + <groupId>cn.iocoder.boot</groupId>
  43 + <artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>
  44 + </dependency>
  45 +
  46 + <!-- Web 相关 -->
  47 + <dependency>
  48 + <groupId>cn.iocoder.boot</groupId>
  49 + <artifactId>yudao-spring-boot-starter-security</artifactId>
  50 + </dependency>
  51 +
  52 + <!-- DB 相关 -->
  53 + <dependency>
  54 + <groupId>cn.iocoder.boot</groupId>
  55 + <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
  56 + </dependency>
  57 +
  58 + <dependency>
  59 + <groupId>cn.iocoder.boot</groupId>
  60 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  61 + </dependency>
  62 +
  63 + <!-- 消息队列相关 -->
  64 + <dependency>
  65 + <groupId>cn.iocoder.boot</groupId>
  66 + <artifactId>yudao-spring-boot-starter-mq</artifactId>
  67 + </dependency>
  68 +
  69 + <!-- Test 测试相关 -->
  70 + <dependency>
  71 + <groupId>cn.iocoder.boot</groupId>
  72 + <artifactId>yudao-spring-boot-starter-test</artifactId>
  73 + <scope>test</scope>
  74 + </dependency>
  75 + <!-- 工具类相关 -->
  76 +
  77 + </dependencies>
  78 +
  79 + <build>
  80 + <!-- 设置构建的 jar 包名 -->
  81 + <finalName>${artifactId}</finalName>
  82 + <plugins>
  83 + <!-- 打包 -->
  84 + <plugin>
  85 + <groupId>org.springframework.boot</groupId>
  86 + <artifactId>spring-boot-maven-plugin</artifactId>
  87 + <configuration>
  88 + <fork>true</fork>
  89 + </configuration>
  90 + <executions>
  91 + <execution>
  92 + <goals>
  93 + <goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
  94 + </goals>
  95 + </execution>
  96 + </executions>
  97 + </plugin>
  98 + </plugins>
  99 + </build>
  100 +
  101 +</project>
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.api;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/api/user/UserApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.api.user;
  2 +
  3 +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
  4 +import cn.iocoder.yudao.module.member.convert.user.UserConvert;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  6 +import cn.iocoder.yudao.module.member.service.user.UserService;
  7 +import org.springframework.stereotype.Service;
  8 +import org.springframework.validation.annotation.Validated;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 会员用户的 API 实现类
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Service
  18 +@Validated
  19 +public class UserApiImpl implements UserApi {
  20 +
  21 + @Resource
  22 + private UserService userService;
  23 +
  24 + @Override
  25 + public UserRespDTO getUser(Long id) {
  26 + UserDO user = userService.getUser(id);
  27 + return UserConvert.INSTANCE.convert2(user);
  28 + }
  29 +
  30 +}
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.admin.address;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.admin.user;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.address;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.http renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
1 1 ### 请求 /login 接口 => 成功
2   -POST {{userServerUrl}}/login
  2 +POST {{userApi}}/login
3 3 Content-Type: application/json
  4 +tenant-id: {{userTenentId}}
4 5  
5 6 {
6 7 "mobile": "15601691300",
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService;
4 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
6 7 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
7   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
8   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
9   -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
10   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
11   -import com.alibaba.fastjson.JSON;
  8 +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
  9 +import cn.iocoder.yudao.module.member.service.auth.AuthService;
  10 +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
12 11 import io.swagger.annotations.Api;
13 12 import io.swagger.annotations.ApiImplicitParam;
14 13 import io.swagger.annotations.ApiImplicitParams;
... ... @@ -18,7 +17,6 @@ import org.springframework.validation.annotation.Validated;
18 17 import org.springframework.web.bind.annotation.*;
19 18  
20 19 import javax.annotation.Resource;
21   -import javax.servlet.http.HttpServletRequest;
22 20 import javax.validation.Valid;
23 21  
24 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -26,15 +24,16 @@ import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getCli
26 24 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
27 25 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
28 26  
29   -@Api(tags = "认证")
  27 +@Api(tags = "APP 端 - 认证")
30 28 @RestController
31 29 @RequestMapping("/")
32 30 @Validated
33 31 @Slf4j
34   -public class SysAuthController {
  32 +public class AppAuthController {
35 33  
36 34 @Resource
37   - private SysAuthService authService;
  35 + private AuthService authService;
  36 +
38 37 @Resource
39 38 private SysSmsCodeService smsCodeService;
40 39 @Resource
... ... @@ -42,35 +41,31 @@ public class SysAuthController {
42 41  
43 42 @PostMapping("/login")
44 43 @ApiOperation("使用手机 + 密码登录")
45   - public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
  44 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  45 + public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) {
46 46 String token = authService.login(reqVO, getClientIP(), getUserAgent());
47 47 // 返回结果
48   - return success(SysAuthLoginRespVO.builder().token(token).build());
  48 + return success(AppAuthLoginRespVO.builder().token(token).build());
49 49 }
50 50  
51 51 @PostMapping("/sms-login")
52 52 @ApiOperation("使用手机 + 验证码登录")
53   - public CommonResult<SysAuthLoginRespVO> smsLogin(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) {
  53 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  54 + public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) {
54 55 String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent());
55 56 // 返回结果
56   - return success(SysAuthLoginRespVO.builder().token(token).build());
  57 + return success(AppAuthLoginRespVO.builder().token(token).build());
57 58 }
58 59  
59 60 @PostMapping("/send-sms-code")
60   - @ApiOperation(value = "发送手机验证码",notes = "不检测该手机号是否已被注册")
61   - public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) {
  61 + @ApiOperation(value = "发送手机验证码")
  62 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  63 + public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid AppAuthSendSmsReqVO reqVO) {
62 64 smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP());
63 65 return success(true);
64 66 }
65 67  
66   - @PostMapping("/send-sms-new-code")
67   - @ApiOperation(value = "发送手机验证码",notes = "检测该手机号是否已被注册,用于修改手机时使用")
68   - public CommonResult<Boolean> sendSmsNewCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) {
69   - smsCodeService.sendSmsNewCode(reqVO);
70   - return success(true);
71   - }
72   -
73   - @GetMapping("/send-sms-code-login")
  68 + @GetMapping("/send-sms-code-login") // TODO 芋艿:post 比较合理
74 69 @ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用")
75 70 public CommonResult<Boolean> sendSmsCodeLogin() {
76 71 smsCodeService.sendSmsCodeLogin(getLoginUserId());
... ... @@ -80,7 +75,8 @@ public class SysAuthController {
80 75 @PostMapping("/reset-password")
81 76 @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用")
82 77 @PreAuthenticated
83   - public CommonResult<Boolean> resetPassword(@RequestBody @Valid MbrAuthResetPasswordReqVO reqVO) {
  78 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  79 + public CommonResult<Boolean> resetPassword(@RequestBody @Valid AppAuthResetPasswordReqVO reqVO) {
84 80 authService.resetPassword(reqVO);
85 81 return success(true);
86 82 }
... ... @@ -88,20 +84,11 @@ public class SysAuthController {
88 84 @PostMapping("/update-password")
89 85 @ApiOperation(value = "修改用户密码",notes = "用户修改密码时使用")
90 86 @PreAuthenticated
91   - public CommonResult<Boolean> updatePassword(@RequestBody @Valid MbrAuthUpdatePasswordReqVO reqVO) {
  87 + public CommonResult<Boolean> updatePassword(@RequestBody @Valid AppAuthUpdatePasswordReqVO reqVO) {
92 88 authService.updatePassword(getLoginUserId(), reqVO);
93 89 return success(true);
94 90 }
95 91  
96   - @PostMapping("/check-sms-code")
97   - @ApiOperation(value = "校验验证码是否正确")
98   - @PreAuthenticated
99   - public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) {
100   - // TODO @宋天:check 的时候,不应该使用 useSmsCode 哈,这样验证码就直接被使用了。另外,check 开头的方法,更多是校验的逻辑,不会有 update 数据的动作。这点,在方法命名上,也是要注意的
101   - smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP());
102   - return success(true);
103   - }
104   -
105 92 // ========== 社交登录相关 ==========
106 93  
107 94 @GetMapping("/social-auth-redirect")
... ... @@ -115,32 +102,33 @@ public class SysAuthController {
115 102 return CommonResult.success(socialService.getAuthorizeUrl(type, redirectUri));
116 103 }
117 104  
118   -
119 105 @PostMapping("/social-login")
120 106 @ApiOperation("社交登录,使用 code 授权码")
121   - public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) {
  107 + public CommonResult<AppAuthLoginRespVO> socialLogin(@RequestBody @Valid AppAuthSocialLoginReqVO reqVO) {
122 108 String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent());
123   - return success(SysAuthLoginRespVO.builder().token(token).build());
  109 + return success(AppAuthLoginRespVO.builder().token(token).build());
124 110 }
125 111  
126   -
127 112 @PostMapping("/social-login2")
128 113 @ApiOperation("社交登录,使用 手机号 + 手机验证码")
129   - public CommonResult<SysAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) {
  114 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  115 + public CommonResult<AppAuthLoginRespVO> socialLogin2(@RequestBody @Valid AppAuthSocialLogin2ReqVO reqVO) {
130 116 String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent());
131   - return success(SysAuthLoginRespVO.builder().token(token).build());
  117 + return success(AppAuthLoginRespVO.builder().token(token).build());
132 118 }
133 119  
134 120 @PostMapping("/social-bind")
135 121 @ApiOperation("社交绑定,使用 code 授权码")
136   - public CommonResult<Boolean> socialBind(@RequestBody @Valid MbrAuthSocialBindReqVO reqVO) {
  122 + @PreAuthenticated
  123 + public CommonResult<Boolean> socialBind(@RequestBody @Valid AppAuthSocialBindReqVO reqVO) {
137 124 authService.socialBind(getLoginUserId(), reqVO);
138 125 return CommonResult.success(true);
139 126 }
140 127  
141 128 @DeleteMapping("/social-unbind")
142 129 @ApiOperation("取消社交绑定")
143   - public CommonResult<Boolean> socialUnbind(@RequestBody MbrAuthSocialUnbindReqVO reqVO) {
  130 + @PreAuthenticated
  131 + public CommonResult<Boolean> socialUnbind(@RequestBody AppAuthSocialUnbindReqVO reqVO) {
144 132 socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId(), UserTypeEnum.MEMBER);
145 133 return CommonResult.success(true);
146 134 }
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.Mobile;
  5 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
  6 +import io.swagger.annotations.ApiModel;
  7 +import io.swagger.annotations.ApiModelProperty;
  8 +import lombok.AllArgsConstructor;
  9 +import lombok.Builder;
  10 +import lombok.Data;
  11 +import lombok.NoArgsConstructor;
  12 +import org.hibernate.validator.constraints.Length;
  13 +
  14 +import javax.validation.constraints.NotBlank;
  15 +import javax.validation.constraints.NotNull;
  16 +import javax.validation.constraints.Pattern;
  17 +
  18 +// TODO 芋艿:code review 相关逻辑
  19 +@ApiModel("APP 端 - 校验验证码 Request VO")
  20 +@Data
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +@Builder
  24 +public class AppAuthCheckCodeReqVO {
  25 +
  26 + @ApiModelProperty(value = "手机号", example = "15601691234")
  27 + @NotBlank(message = "手机号不能为空")
  28 + @Mobile
  29 + private String mobile;
  30 +
  31 + @ApiModelProperty(value = "手机验证码", required = true, example = "1024")
  32 + @NotBlank(message = "手机验证码不能为空")
  33 + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
  34 + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
  35 + private String code;
  36 +
  37 + @ApiModelProperty(value = "发送场景", example = "1", notes = "对应 MbrSmsSceneEnum 枚举")
  38 + @NotNull(message = "发送场景不能为空")
  39 + @InEnum(SysSmsSceneEnum.class)
  40 + private Integer scene;
  41 +
  42 +}
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthLoginReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.Mobile;
4 4 import io.swagger.annotations.ApiModel;
... ... @@ -11,12 +11,12 @@ import org.hibernate.validator.constraints.Length;
11 11  
12 12 import javax.validation.constraints.NotEmpty;
13 13  
14   -@ApiModel("手机 + 密码登录 Request VO")
  14 +@ApiModel("APP 端 - 手机 + 密码登录 Request VO")
15 15 @Data
16 16 @NoArgsConstructor
17 17 @AllArgsConstructor
18 18 @Builder
19   -public class SysAuthLoginReqVO {
  19 +public class AppAuthLoginReqVO {
20 20  
21 21 @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
22 22 @NotEmpty(message = "手机号不能为空")
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthLoginRespVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
... ... @@ -7,12 +7,12 @@ import lombok.Builder;
7 7 import lombok.Data;
8 8 import lombok.NoArgsConstructor;
9 9  
10   -@ApiModel("手机密码登录 Response VO")
  10 +@ApiModel("APP 端 - 手机密码登录 Response VO")
11 11 @Data
12 12 @NoArgsConstructor
13 13 @AllArgsConstructor
14 14 @Builder
15   -public class SysAuthLoginRespVO {
  15 +public class AppAuthLoginRespVO {
16 16  
17 17 @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma")
18 18 private String token;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthResetPasswordReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthResetPasswordReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
  3 +import cn.iocoder.yudao.framework.common.validation.Mobile;
3 4 import io.swagger.annotations.ApiModel;
4 5 import io.swagger.annotations.ApiModelProperty;
5 6 import lombok.AllArgsConstructor;
... ... @@ -8,15 +9,17 @@ import lombok.Data;
8 9 import lombok.NoArgsConstructor;
9 10 import org.hibernate.validator.constraints.Length;
10 11  
  12 +import javax.validation.constraints.NotBlank;
11 13 import javax.validation.constraints.NotEmpty;
12 14 import javax.validation.constraints.Pattern;
13 15  
14   -@ApiModel("重置密码 Request VO")
  16 +// TODO 芋艿:code review 相关逻辑
  17 +@ApiModel("APP 端 - 重置密码 Request VO")
15 18 @Data
16 19 @NoArgsConstructor
17 20 @AllArgsConstructor
18 21 @Builder
19   -public class MbrAuthResetPasswordReqVO {
  22 +public class AppAuthResetPasswordReqVO {
20 23  
21 24 @ApiModelProperty(value = "新密码", required = true, example = "buzhidao")
22 25 @NotEmpty(message = "新密码不能为空")
... ... @@ -29,4 +32,9 @@ public class MbrAuthResetPasswordReqVO {
29 32 @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
30 33 private String code;
31 34  
  35 + @ApiModelProperty(value = "手机号",required = true,example = "15878962356")
  36 + @NotBlank(message = "手机号不能为空")
  37 + @Mobile
  38 + private String mobile;
  39 +
32 40 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthSendSmsReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSendSmsReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.Mobile;
5   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
  5 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
6 6 import io.swagger.annotations.ApiModel;
7 7 import io.swagger.annotations.ApiModelProperty;
8 8 import lombok.Data;
... ... @@ -10,10 +10,10 @@ import lombok.experimental.Accessors;
10 10  
11 11 import javax.validation.constraints.NotNull;
12 12  
13   -@ApiModel("发送手机验证码 Response VO")
  13 +@ApiModel("APP 端 - 发送手机验证码 Response VO")
14 14 @Data
15 15 @Accessors(chain = true)
16   -public class SysAuthSendSmsReqVO {
  16 +public class AppAuthSendSmsReqVO {
17 17  
18 18 @ApiModelProperty(value = "手机号", example = "15601691234")
19 19 @Mobile
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthSmsLoginReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsLoginReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.Mobile;
4 4 import io.swagger.annotations.ApiModel;
... ... @@ -12,12 +12,12 @@ import org.hibernate.validator.constraints.Length;
12 12 import javax.validation.constraints.NotEmpty;
13 13 import javax.validation.constraints.Pattern;
14 14  
15   -@ApiModel("手机 + 验证码登录 Request VO")
  15 +@ApiModel("APP 端 - 手机 + 验证码登录 Request VO")
16 16 @Data
17 17 @NoArgsConstructor
18 18 @AllArgsConstructor
19 19 @Builder
20   -public class SysAuthSmsLoginReqVO {
  20 +public class AppAuthSmsLoginReqVO {
21 21  
22 22 @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
23 23 @NotEmpty(message = "手机号不能为空")
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialBindReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialBindReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
... ... @@ -12,12 +12,12 @@ import lombok.NoArgsConstructor;
12 12 import javax.validation.constraints.NotEmpty;
13 13 import javax.validation.constraints.NotNull;
14 14  
15   -@ApiModel("社交绑定 Request VO,使用 code 授权码")
  15 +@ApiModel("APP 端 - 社交绑定 Request VO,使用 code 授权码")
16 16 @Data
17 17 @NoArgsConstructor
18 18 @AllArgsConstructor
19 19 @Builder
20   -public class MbrAuthSocialBindReqVO {
  20 +public class AppAuthSocialBindReqVO {
21 21  
22 22 @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值")
23 23 @InEnum(SysSocialTypeEnum.class)
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialLogin2ReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialLogin2ReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
... ... @@ -14,12 +14,12 @@ import javax.validation.constraints.NotEmpty;
14 14 import javax.validation.constraints.NotNull;
15 15 import javax.validation.constraints.Pattern;
16 16  
17   -@ApiModel("社交登录 Request VO,使用 code 授权码 + 账号密码")
  17 +@ApiModel("APP 端 - 社交登录 Request VO,使用 code 授权码 + 账号密码")
18 18 @Data
19 19 @NoArgsConstructor
20 20 @AllArgsConstructor
21 21 @Builder
22   -public class MbrAuthSocialLogin2ReqVO {
  22 +public class AppAuthSocialLogin2ReqVO {
23 23  
24 24 @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值")
25 25 @InEnum(SysSocialTypeEnum.class)
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialLoginReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialLoginReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
... ... @@ -12,12 +12,12 @@ import lombok.NoArgsConstructor;
12 12 import javax.validation.constraints.NotEmpty;
13 13 import javax.validation.constraints.NotNull;
14 14  
15   -@ApiModel("社交登录 Request VO,使用 code 授权码")
  15 +@ApiModel("APP 端 - 社交登录 Request VO,使用 code 授权码")
16 16 @Data
17 17 @NoArgsConstructor
18 18 @AllArgsConstructor
19 19 @Builder
20   -public class MbrAuthSocialLoginReqVO {
  20 +public class AppAuthSocialLoginReqVO {
21 21  
22 22 @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值")
23 23 @InEnum(SysSocialTypeEnum.class)
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialUnbindReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialUnbindReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
... ... @@ -12,12 +12,12 @@ import lombok.NoArgsConstructor;
12 12 import javax.validation.constraints.NotEmpty;
13 13 import javax.validation.constraints.NotNull;
14 14  
15   -@ApiModel("取消社交绑定 Request VO,使用 code 授权码")
  15 +@ApiModel("APP 端 - 取消社交绑定 Request VO,使用 code 授权码")
16 16 @Data
17 17 @NoArgsConstructor
18 18 @AllArgsConstructor
19 19 @Builder
20   -public class MbrAuthSocialUnbindReqVO {
  20 +public class AppAuthSocialUnbindReqVO {
21 21  
22 22 @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值")
23 23 @InEnum(SysSocialTypeEnum.class)
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthUpdatePasswordReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthUpdatePasswordReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
2 2  
3 3 import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
... ... @@ -11,12 +11,13 @@ import org.hibernate.validator.constraints.Length;
11 11 import javax.validation.constraints.NotBlank;
12 12 import javax.validation.constraints.NotEmpty;
13 13  
14   -@ApiModel("修改密码 Request VO")
  14 +// TODO 芋艿:code review 相关逻辑
  15 +@ApiModel("APP 端 - 修改密码 Request VO")
15 16 @Data
16 17 @NoArgsConstructor
17 18 @AllArgsConstructor
18 19 @Builder
19   -public class MbrAuthUpdatePasswordReqVO {
  20 +public class AppAuthUpdatePasswordReqVO {
20 21  
21 22 @ApiModelProperty(value = "用户旧密码", required = true, example = "123456")
22 23 @NotBlank(message = "旧密码不能为空")
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.http renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.http
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java
1   -package cn.iocoder.yudao.userserver.modules.member.controller.user;
  1 +package cn.iocoder.yudao.module.member.controller.app.user;
2 2  
3   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
4   -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
5 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 4 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
7   -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
8   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
9   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
10   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
  5 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
  6 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
  7 +import cn.iocoder.yudao.module.member.convert.user.UserConvert;
  8 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  9 +import cn.iocoder.yudao.module.member.service.user.UserService;
11 10 import io.swagger.annotations.Api;
12 11 import io.swagger.annotations.ApiOperation;
13 12 import lombok.extern.slf4j.Slf4j;
... ... @@ -17,62 +16,55 @@ import org.springframework.web.multipart.MultipartFile;
17 16  
18 17 import javax.annotation.Resource;
19 18 import javax.validation.Valid;
20   -
21 19 import java.io.IOException;
22 20  
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
23 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
24   -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
25 23 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
26   -import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY;
  24 +import static cn.iocoder.yudao.module.member.enums.MemberErrorCodeConstants.FILE_IS_EMPTY;
27 25  
28   -@Api(tags = "用户个人中心")
  26 +@Api(tags = "APP 端 - 用户个人中心")
29 27 @RestController
30   -@RequestMapping("/member/user/profile")
  28 +@RequestMapping("/member/user")
31 29 @Validated
32 30 @Slf4j
33   -public class SysUserProfileController {
34   -
35   - @Resource
36   - private MbrUserService userService;
  31 +public class AppUserController {
37 32  
38 33 @Resource
39   - private SysSmsCodeService smsCodeService;
  34 + private UserService userService;
40 35  
41 36 @PutMapping("/update-nickname")
42 37 @ApiOperation("修改用户昵称")
43 38 @PreAuthenticated
44   - public CommonResult<Boolean> updateNickname(@RequestParam("nickname") String nickname) {
45   - userService.updateNickname(getLoginUserId(), nickname);
  39 + public CommonResult<Boolean> updateUserNickname(@RequestParam("nickname") String nickname) {
  40 + userService.updateUserNickname(getLoginUserId(), nickname);
46 41 return success(true);
47 42 }
48 43  
49 44 @PutMapping("/update-avatar")
50 45 @ApiOperation("修改用户头像")
51 46 @PreAuthenticated
52   - public CommonResult<String> updateAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException {
  47 + public CommonResult<String> updateUserAvatar(@RequestParam("avatarFile") MultipartFile file) throws IOException {
53 48 if (file.isEmpty()) {
54   - throw ServiceExceptionUtil.exception(FILE_IS_EMPTY);
  49 + throw exception(FILE_IS_EMPTY);
55 50 }
56   - String avatar = userService.updateAvatar(getLoginUserId(), file.getInputStream());
  51 + String avatar = userService.updateUserAvatar(getLoginUserId(), file.getInputStream());
57 52 return success(avatar);
58 53 }
59 54  
60 55 @GetMapping("/get")
61 56 @ApiOperation("获得基本信息")
62 57 @PreAuthenticated
63   - public CommonResult<MbrUserInfoRespVO> getUserInfo() {
64   - return success(userService.getUserInfo(getLoginUserId()));
  58 + public CommonResult<AppUserInfoRespVO> getUserInfo() {
  59 + UserDO user = userService.getUser(getLoginUserId());
  60 + return success(UserConvert.INSTANCE.convert(user));
65 61 }
66 62  
67 63 @PostMapping("/update-mobile")
68 64 @ApiOperation(value = "修改用户手机")
69 65 @PreAuthenticated
70   - public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) {
71   - // 校验验证码
72   - // TODO @宋天:统一到 userService.updateMobile 方法里
73   - smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
74   -
75   - userService.updateMobile(getLoginUserId(), reqVO);
  66 + public CommonResult<Boolean> updateMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) {
  67 + userService.updateUserMobile(getLoginUserId(), reqVO);
76 68 return success(true);
77 69 }
78 70  
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserInfoRespVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserInfoRespVO.java
1   -package cn.iocoder.yudao.userserver.modules.member.controller.user.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.user.vo;
2 2  
3 3 import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
... ... @@ -6,11 +6,11 @@ import lombok.AllArgsConstructor;
6 6 import lombok.Data;
7 7 import lombok.NoArgsConstructor;
8 8  
9   -@ApiModel("用户个人信息 Response VO")
  9 +@ApiModel("APP 端 - 用户个人信息 Response VO")
10 10 @Data
11 11 @NoArgsConstructor
12 12 @AllArgsConstructor
13   -public class MbrUserInfoRespVO {
  13 +public class AppUserInfoRespVO {
14 14  
15 15 @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
16 16 private String nickname;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserUpdateMobileReqVO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java
1   -package cn.iocoder.yudao.userserver.modules.member.controller.user.vo;
  1 +package cn.iocoder.yudao.module.member.controller.app.user.vo;
2 2  
  3 +import cn.iocoder.yudao.framework.common.validation.Mobile;
3 4 import io.swagger.annotations.ApiModel;
4 5 import io.swagger.annotations.ApiModelProperty;
5 6 import lombok.AllArgsConstructor;
... ... @@ -12,12 +13,12 @@ import javax.validation.constraints.NotBlank;
12 13 import javax.validation.constraints.NotEmpty;
13 14 import javax.validation.constraints.Pattern;
14 15  
15   -@ApiModel("修改手机 Request VO")
  16 +@ApiModel("APP 端 - 修改手机 Request VO")
16 17 @Data
17 18 @NoArgsConstructor
18 19 @AllArgsConstructor
19 20 @Builder
20   -public class MbrUserUpdateMobileReqVO {
  21 +public class AppUserUpdateMobileReqVO {
21 22  
22 23 @ApiModelProperty(value = "手机验证码", required = true, example = "1024")
23 24 @NotEmpty(message = "手机验证码不能为空")
... ... @@ -27,9 +28,22 @@ public class MbrUserUpdateMobileReqVO {
27 28  
28 29 @ApiModelProperty(value = "手机号",required = true,example = "15823654487")
29 30 @NotBlank(message = "手机号不能为空")
30   - // TODO @宋天:手机校验,直接使用 @Mobile 哈
31 31 @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
32   - @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
  32 + @Mobile
33 33 private String mobile;
34 34  
  35 + @ApiModelProperty(value = "原手机验证码", required = true, example = "1024")
  36 + @NotEmpty(message = "原手机验证码不能为空")
  37 + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
  38 + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
  39 + private String oldCode;
  40 +
  41 + // TODO @芋艿:oldMobile 应该不用传递
  42 +
  43 + @ApiModelProperty(value = "原手机号",required = true,example = "15823654487")
  44 + @NotBlank(message = "手机号不能为空")
  45 + @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
  46 + @Mobile
  47 + private String oldMobile;
  48 +
35 49 }
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/package-info.java 0 → 100644
  1 +/**
  2 + * 提供 RESTful API 给前端:
  3 + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
  4 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目
  5 + */
  6 +package cn.iocoder.yudao.module.member.controller;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/auth/SysAuthConvert.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
1   -package cn.iocoder.yudao.userserver.modules.system.convert.auth;
  1 +package cn.iocoder.yudao.module.member.convert.auth;
2 2  
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 4 import cn.iocoder.yudao.framework.security.core.LoginUser;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
6 6 import org.mapstruct.Mapper;
7 7 import org.mapstruct.Mapping;
8 8 import org.mapstruct.factory.Mappers;
9 9  
10 10 @Mapper
11   -public interface SysAuthConvert {
  11 +public interface AuthConvert {
12 12  
13   - SysAuthConvert INSTANCE = Mappers.getMapper(SysAuthConvert.class);
  13 + AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class);
14 14  
15 15 @Mapping(source = "mobile", target = "username")
16   - LoginUser convert0(MbrUserDO bean);
  16 + LoginUser convert0(UserDO bean);
17 17  
18   - default LoginUser convert(MbrUserDO bean) {
  18 + default LoginUser convert(UserDO bean) {
19 19 // 目的,为了设置 UserTypeEnum.MEMBER.getValue()
20 20 return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue());
21 21 }
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/convert/package-info.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/package-info.java
... ... @@ -3,4 +3,4 @@
3 3 *
4 4 * 目前使用 MapStruct 框架
5 5 */
6   -package cn.iocoder.yudao.coreservice.modules.member.convert;
  6 +package cn.iocoder.yudao.module.member.convert;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.convert.user;
  2 +
  3 +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
  4 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.factory.Mappers;
  8 +
  9 +@Mapper
  10 +public interface UserConvert {
  11 +
  12 + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
  13 +
  14 + AppUserInfoRespVO convert(UserDO bean);
  15 +
  16 + UserRespDTO convert2(UserDO bean);
  17 +}
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/dataobject/sms/SysSmsCodeDO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/sms/SysSmsCodeDO.java
1   -package cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms;
  1 +package cn.iocoder.yudao.module.member.dal.dataobject.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import com.baomidou.mybatisplus.annotation.TableName;
5 5 import lombok.*;
6   -import lombok.experimental.Accessors;
7 6  
8 7 import java.util.Date;
9 8  
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/dal/dataobject/user/MbrUserDO.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/UserDO.java
1   -package cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user;
  1 +package cn.iocoder.yudao.module.member.dal.dataobject.user;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
... ... @@ -10,7 +10,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 10 import java.util.Date;
11 11  
12 12 /**
13   - * 会员中心的用户 DO
  13 + * 会员用户 DO
14 14 *
15 15 * uk_mobile 索引:基于 {@link #mobile} 字段
16 16 *
... ... @@ -22,7 +22,7 @@ import java.util.Date;
22 22 @Builder
23 23 @NoArgsConstructor
24 24 @AllArgsConstructor
25   -public class MbrUserDO extends TenantBaseDO {
  25 +public class UserDO extends TenantBaseDO {
26 26  
27 27 /**
28 28 * 用户ID
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/sms/SysSmsCodeMapper.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/sms/SysSmsCodeMapper.java
1   -package cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms;
  1 +package cn.iocoder.yudao.module.member.dal.mysql.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
5   -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO;
6 6 import org.apache.ibatis.annotations.Mapper;
7 7  
  8 +// TODO @芋艿:拿到 system 模块下
8 9 @Mapper
9 10 public interface SysSmsCodeMapper extends BaseMapperX<SysSmsCodeDO> {
10 11  
... ... @@ -13,14 +14,15 @@ public interface SysSmsCodeMapper extends BaseMapperX&lt;SysSmsCodeDO&gt; {
13 14 *
14 15 * @param mobile 手机号
15 16 * @param scene 发送场景,选填
  17 + * @param code 验证码 选填
16 18 * @return 手机验证码
17 19 */
18   - default SysSmsCodeDO selectLastByMobile(String mobile, Integer scene) {
  20 + default SysSmsCodeDO selectLastByMobile(String mobile,String code,Integer scene) {
19 21 return selectOne(new QueryWrapperX<SysSmsCodeDO>()
20 22 .eq("mobile", mobile)
21 23 .eqIfPresent("scene", scene)
  24 + .eqIfPresent("code", code)
22 25 .orderByDesc("id")
23 26 .last("LIMIT 1"));
24 27 }
25   -
26 28 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/dal/mysql/user/MbrUserMapper.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/UserMapper.java
1   -package cn.iocoder.yudao.userserver.modules.member.dal.mysql.user;
  1 +package cn.iocoder.yudao.module.member.dal.mysql.user;
2 2  
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
5 5 import org.apache.ibatis.annotations.Mapper;
6 6  
7 7 /**
8   - * MbrUserDO Mapper
  8 + * 会员 User Mapper
9 9 *
10 10 * @author 芋道源码
11 11 */
12 12 @Mapper
13   -public interface MbrUserMapper extends BaseMapperX<MbrUserDO> {
  13 +public interface UserMapper extends BaseMapperX<UserDO> {
14 14  
15   - default MbrUserDO selectByMobile(String mobile) {
16   - return selectOne(MbrUserDO::getMobile, mobile);
  15 + default UserDO selectByMobile(String mobile) {
  16 + return selectOne(UserDO::getMobile, mobile);
17 17 }
18 18  
19 19 }
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java 0 → 100644
  1 +/**
  2 + * DAL = Data Access Layer 数据访问层
  3 + * 1. data object:数据对象
  4 + * 2. redis:Redis 的 CRUD 操作
  5 + * 3. mysql:MySQL 的 CRUD 操作
  6 + *
  7 + * 其中,MySQL 的表以 mbr_ 作为前缀
  8 + */
  9 +package cn.iocoder.yudao.module.member.dal;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java 0 → 100644
  1 +/**
  2 + * 占位,后续有类后,可以删除,避免 package 无法提交到 Git 上
  3 + */
  4 +package cn.iocoder.yudao.module.member.dal.redis;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/enums/MemberErrorCodeConstants.java
1   -package cn.iocoder.yudao.userserver.modules.member.enums;
  1 +package cn.iocoder.yudao.module.member.enums;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4  
... ... @@ -7,11 +7,12 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
7 7 *
8 8 * member 系统,使用 1-004-000-000 段
9 9 */
10   -public interface MbrErrorCodeConstants {
  10 +public interface MemberErrorCodeConstants {
11 11  
12 12 // ==========用户相关 1004001000============
13 13 ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
14 14  
15 15 // ==========文件相关 1004002000 ===========
16 16 ErrorCode FILE_IS_EMPTY = new ErrorCode(1004002000, "文件为空");
  17 +
17 18 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/SysErrorCodeConstants.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/enums/SysErrorCodeConstants.java
1   -package cn.iocoder.yudao.userserver.modules.system.enums;
  1 +package cn.iocoder.yudao.module.member.enums;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4  
... ... @@ -24,9 +24,9 @@ public interface SysErrorCodeConstants {
24 24 ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量");
25 25 ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率");
26 26 ErrorCode USER_SMS_CODE_IS_EXISTS = new ErrorCode(1005001006, "手机号已被使用");
  27 + ErrorCode USER_SMS_CODE_IS_UNUSED = new ErrorCode(1005001006, "验证码未被使用");
27 28  
28 29 // ========== 用户模块 1005002000 ==========
29 30 ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在");
30   - ErrorCode USER_CODE_FAILED = new ErrorCode(1005002002, "验证码不匹配");
31 31 ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1005002003, "密码校验失败");
32 32 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/sms/SysSmsSceneEnum.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/enums/sms/SysSmsSceneEnum.java
1   -package cn.iocoder.yudao.userserver.modules.system.enums.sms;
  1 +package cn.iocoder.yudao.module.member.enums.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4 4 import lombok.AllArgsConstructor;
... ... @@ -15,15 +15,26 @@ import java.util.Arrays;
15 15 @AllArgsConstructor
16 16 public enum SysSmsSceneEnum implements IntArrayValuable {
17 17  
18   - LOGIN_BY_SMS(1, "手机号登陆"),
19   - CHANGE_MOBILE_BY_SMS(2, "更换手机号"),
20   - FORGET_MOBILE_BY_SMS(3, "忘记密码"),
21   - CHECK_CODE_BY_SMS(4, "审核验证码"),
  18 + LOGIN_BY_SMS(1,SysSmsTemplateCodeConstants.USER_SMS_LOGIN, "手机号登陆"),
  19 + CHANGE_MOBILE_BY_SMS(2,SysSmsTemplateCodeConstants.USER_SMS_UPDATE_MOBILE, "更换手机号"),
  20 + FORGET_MOBILE_BY_SMS(3,SysSmsTemplateCodeConstants.USER_SMS_RESET_PASSWORD, "忘记密码"),
22 21 ;
23 22  
24 23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray();
25 24  
  25 + /**
  26 + * 验证那场景编号
  27 + */
26 28 private final Integer scene;
  29 +
  30 + /**
  31 + * 模版编码
  32 + */
  33 + private final String code;
  34 +
  35 + /**
  36 + * 描述
  37 + */
27 38 private final String name;
28 39  
29 40 @Override
... ... @@ -31,4 +42,13 @@ public enum SysSmsSceneEnum implements IntArrayValuable {
31 42 return ARRAYS;
32 43 }
33 44  
  45 + public static String getCodeByScene(Integer scene){
  46 + for (SysSmsSceneEnum value : values()) {
  47 + if (value.getScene().equals(scene)){
  48 + return value.getCode();
  49 + }
  50 + }
  51 + return null;
  52 + }
  53 +
34 54 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/sms/SysSmsTemplateCodeConstants.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/enums/sms/SysSmsTemplateCodeConstants.java
1   -package cn.iocoder.yudao.userserver.modules.system.enums.sms;
  1 +package cn.iocoder.yudao.module.member.enums.sms;
2 2  
3 3 /**
4 4 * yudao-user-server 使用到的短信模板的 Code 编码的枚举
... ... @@ -12,4 +12,14 @@ public interface SysSmsTemplateCodeConstants {
12 12 */
13 13 String USER_SMS_LOGIN = "user-sms-login";
14 14  
  15 + /**
  16 + * 用户忘记密码
  17 + */
  18 + String USER_SMS_RESET_PASSWORD = "user-sms-reset-password";
  19 +
  20 + /**
  21 + * 用户更新手机号
  22 + */
  23 + String USER_SMS_UPDATE_MOBILE = "user-sms-update-mobile";
  24 +
15 25 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/package-info.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/package-info.java
1 1 /**
2   - * 属于整个 yudao-user-server 的 framework 封装
  2 + * 属于 yudao-module-member-impl 的封装
3 3 *
4 4 * @author 芋道源码
5 5 */
6   -package cn.iocoder.yudao.userserver.framework;
  6 +package cn.iocoder.yudao.module.member.framework;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/framework/sms/SmsCodeConfiguration.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/sms/SmsCodeConfiguration.java
1   -package cn.iocoder.yudao.userserver.modules.system.framework.sms;
  1 +package cn.iocoder.yudao.module.member.framework.sms;
2 2  
3 3 import org.springframework.boot.context.properties.EnableConfigurationProperties;
4 4 import org.springframework.context.annotation.Configuration;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/framework/sms/SmsCodeProperties.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/framework/sms/SmsCodeProperties.java
1   -package cn.iocoder.yudao.userserver.modules.system.framework.sms;
  1 +package cn.iocoder.yudao.module.member.framework.sms;
2 2  
3 3 import lombok.Data;
4 4 import org.springframework.boot.context.properties.ConfigurationProperties;
... ...
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysAuthService.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthService.java
1   -package cn.iocoder.yudao.userserver.modules.system.service.auth;
  1 +package cn.iocoder.yudao.module.member.service.auth;
2 2  
3 3 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
4   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
  4 +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
5 5  
6 6 import javax.validation.Valid;
7 7  
8 8 /**
9   - * 用户前台的认证 Service 接口
  9 + * 会员的认证 Service 接口
10 10 *
11 11 * 提供用户的账号密码登录、token 的校验等认证相关的功能
12 12 *
13 13 * @author 芋道源码
14 14 */
15   -public interface SysAuthService extends SecurityAuthFrameworkService {
  15 +public interface AuthService extends SecurityAuthFrameworkService {
16 16  
17 17 /**
18 18 * 手机 + 密码登录
... ... @@ -22,7 +22,7 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
22 22 * @param userAgent 用户 UA
23 23 * @return 身份令牌,使用 JWT 方式
24 24 */
25   - String login(@Valid SysAuthLoginReqVO reqVO, String userIp, String userAgent);
  25 + String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent);
26 26  
27 27 /**
28 28 * 手机 + 验证码登陆
... ... @@ -32,7 +32,7 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
32 32 * @param userAgent 用户 UA
33 33 * @return 身份令牌,使用 JWT 方式
34 34 */
35   - String smsLogin(@Valid SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent);
  35 + String smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent);
36 36  
37 37  
38 38 /**
... ... @@ -43,7 +43,7 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
43 43 * @param userAgent 用户 UA
44 44 * @return 身份令牌,使用 JWT 方式
45 45 */
46   - String socialLogin(@Valid MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent);
  46 + String socialLogin(@Valid AppAuthSocialLoginReqVO reqVO, String userIp, String userAgent);
47 47  
48 48 /**
49 49 * 社交登录,使用 手机号 + 手机验证码
... ... @@ -53,7 +53,7 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
53 53 * @param userAgent 用户 UA
54 54 * @return 身份令牌,使用 JWT 方式
55 55 */
56   - String socialLogin2(@Valid MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent);
  56 + String socialLogin2(@Valid AppAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent);
57 57  
58 58 /**
59 59 * 社交绑定,使用 code 授权码
... ... @@ -61,25 +61,19 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
61 61 * @param userId 用户编号
62 62 * @param reqVO 绑定信息
63 63 */
64   - void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO);
  64 + void socialBind(Long userId, @Valid AppAuthSocialBindReqVO reqVO);
65 65  
66 66 /**
67 67 * 修改用户密码
68 68 * @param userId 用户id
69 69 * @param userReqVO 用户请求实体类
70 70 */
71   - void updatePassword(Long userId, @Valid MbrAuthUpdatePasswordReqVO userReqVO);
  71 + void updatePassword(Long userId, AppAuthUpdatePasswordReqVO userReqVO);
72 72  
73 73 /**
74 74 * 忘记密码
75 75 * @param userReqVO 用户请求实体类
76 76 */
77   - void resetPassword(MbrAuthResetPasswordReqVO userReqVO);
  77 + void resetPassword(AppAuthResetPasswordReqVO userReqVO);
78 78  
79   - /**
80   - * 检测手机与验证码是否匹配
81   - * @param phone 手机号
82   - * @param code 验证码
83   - */
84   - void checkIfMobileMatchCodeAndDeleteCode(String phone,String code);
85 79 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java
1   -package cn.iocoder.yudao.userserver.modules.system.service.auth.impl;
  1 +package cn.iocoder.yudao.module.member.service.auth;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
6 5 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
7 6 import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
8 7 import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
... ... @@ -15,18 +14,18 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
15 14 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
16 15 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
17 16 import cn.iocoder.yudao.framework.security.core.LoginUser;
18   -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
19   -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
20   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
21   -import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert;
22   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
23   -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
24   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
  17 +import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;
  18 +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
  19 +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
  20 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  21 +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper;
  22 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
  23 +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
  24 +import cn.iocoder.yudao.module.member.service.user.UserService;
25 25 import com.google.common.annotations.VisibleForTesting;
26 26 import lombok.extern.slf4j.Slf4j;
27 27 import me.zhyd.oauth.model.AuthUser;
28 28 import org.springframework.context.annotation.Lazy;
29   -import org.springframework.data.redis.core.StringRedisTemplate;
30 29 import org.springframework.security.authentication.AuthenticationManager;
31 30 import org.springframework.security.authentication.BadCredentialsException;
32 31 import org.springframework.security.authentication.DisabledException;
... ... @@ -40,31 +39,28 @@ import org.springframework.stereotype.Service;
40 39 import org.springframework.transaction.annotation.Transactional;
41 40  
42 41 import javax.annotation.Resource;
43   -import javax.validation.Valid;
44 42 import java.util.List;
45 43 import java.util.Objects;
46 44  
47 45 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
48 46 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
49   -import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*;
  47 +import static cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants.*;
50 48  
51 49 /**
52   - * Auth Service 实现类
  50 + * 会员的认证 Service 接口
53 51 *
54 52 * @author 芋道源码
55 53 */
56 54 @Service
57 55 @Slf4j
58   -public class SysAuthServiceImpl implements SysAuthService {
59   -
60   - private static final UserTypeEnum USER_TYPE_ENUM = UserTypeEnum.MEMBER;
  56 +public class AuthServiceImpl implements AuthService {
61 57  
62 58 @Resource
63 59 @Lazy // 延迟加载,因为存在相互依赖的问题
64 60 private AuthenticationManager authenticationManager;
65 61  
66 62 @Resource
67   - private MbrUserService userService;
  63 + private UserService userService;
68 64 @Resource
69 65 private SysSmsCodeService smsCodeService;
70 66 @Resource
... ... @@ -75,27 +71,23 @@ public class SysAuthServiceImpl implements SysAuthService {
75 71 private SysSocialCoreService socialService;
76 72  
77 73 @Resource
78   - private StringRedisTemplate stringRedisTemplate;
79   - @Resource
80 74 private PasswordEncoder passwordEncoder;
81 75 @Resource
82   - private MbrUserMapper userMapper;
83   -
84   - private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER;
  76 + private UserMapper userMapper;
85 77  
86 78 @Override
87 79 public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
88 80 // 获取 username 对应的 SysUserDO
89   - MbrUserDO user = userService.getUserByMobile(mobile);
  81 + UserDO user = userService.getUserByMobile(mobile);
90 82 if (user == null) {
91 83 throw new UsernameNotFoundException(mobile);
92 84 }
93 85 // 创建 LoginUser 对象
94   - return SysAuthConvert.INSTANCE.convert(user);
  86 + return AuthConvert.INSTANCE.convert(user);
95 87 }
96 88  
97 89 @Override
98   - public String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent) {
  90 + public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) {
99 91 // 使用手机 + 密码,进行登录。
100 92 LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword());
101 93  
... ... @@ -105,80 +97,77 @@ public class SysAuthServiceImpl implements SysAuthService {
105 97  
106 98 @Override
107 99 @Transactional
108   - public String smsLogin(SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent) {
  100 + public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) {
109 101 // 校验验证码
110 102 smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(),
111 103 reqVO.getCode(), userIp);
112 104  
113 105 // 获得获得注册用户
114   - MbrUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp);
  106 + UserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp);
115 107 Assert.notNull(user, "获取用户失败,结果为空");
116 108  
117 109 // 执行登陆
118 110 this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS);
119   - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
  111 + LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
120 112  
121 113 // 缓存登录用户到 Redis 中,返回 sessionId 编号
122 114 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
123 115 }
124 116  
125 117 @Override
126   - public String socialLogin(MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
  118 + public String socialLogin(AppAuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
127 119 // 使用 code 授权码,进行登录
128 120 AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
129 121 org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
130 122  
131 123 // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错
132 124 String unionId = socialService.getAuthUserUnionId(authUser);
133   - List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, USER_TYPE_ENUM);
  125 + List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType());
134 126 if (CollUtil.isEmpty(socialUsers)) {
135 127 throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
136 128 }
137 129  
138 130 // 自动登录
139   - MbrUserDO user = userService.getUser(socialUsers.get(0).getUserId());
  131 + UserDO user = userService.getUser(socialUsers.get(0).getUserId());
140 132 if (user == null) {
141 133 throw exception(USER_NOT_EXISTS);
142 134 }
143 135 this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS);
144 136  
145 137 // 创建 LoginUser 对象
146   - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
  138 + LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
147 139  
148 140 // 绑定社交用户(更新)
149   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
  141 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
150 142  
151 143 // 缓存登录用户到 Redis 中,返回 sessionId 编号
152 144 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
153 145 }
154 146  
155 147 @Override
156   - public String socialLogin2(MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
  148 + public String socialLogin2(AppAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
157 149 AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
158 150 org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
159 151  
160 152 // 使用手机号、手机验证码登录
161   - SysAuthSmsLoginReqVO loginReqVO = SysAuthSmsLoginReqVO
162   - .builder()
163   - .mobile(reqVO.getMobile())
164   - .code(reqVO.getSmsCode())
165   - .build();
  153 + AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder()
  154 + .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build();
166 155 String sessionId = this.smsLogin(loginReqVO, userIp, userAgent);
167 156 LoginUser loginUser = userSessionCoreService.getLoginUser(sessionId);
168 157  
169 158 // 绑定社交用户(新增)
170   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
  159 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
171 160 return sessionId;
172 161 }
173 162  
174 163 @Override
175   - public void socialBind(Long userId, MbrAuthSocialBindReqVO reqVO) {
  164 + public void socialBind(Long userId, AppAuthSocialBindReqVO reqVO) {
176 165 // 使用 code 授权码,进行登录
177 166 AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
178 167 org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
179 168  
180 169 // 绑定社交用户(新增)
181   - socialService.bindSocialUser(userId, reqVO.getType(), authUser, USER_TYPE_ENUM);
  170 + socialService.bindSocialUser(userId, reqVO.getType(), authUser, getUserType());
182 171 }
183 172  
184 173 private LoginUser login0(String username, String password) {
... ... @@ -188,7 +177,8 @@ public class SysAuthServiceImpl implements SysAuthService {
188 177 try {
189 178 // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证
190 179 // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
191   - authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
  180 + authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken(
  181 + username, password, getUserType()));
192 182 } catch (BadCredentialsException badCredentialsException) {
193 183 this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS);
194 184 throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
... ... @@ -208,7 +198,7 @@ public class SysAuthServiceImpl implements SysAuthService {
208 198  
209 199 private void createLoginLog(String mobile, SysLoginLogTypeEnum logTypeEnum, SysLoginResultEnum loginResult) {
210 200 // 获得用户
211   - MbrUserDO user = userService.getUserByMobile(mobile);
  201 + UserDO user = userService.getUserByMobile(mobile);
212 202 // 插入登录日志
213 203 SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
214 204 reqDTO.setLogType(logTypeEnum.getType());
... ... @@ -246,10 +236,11 @@ public class SysAuthServiceImpl implements SysAuthService {
246 236 return;
247 237 }
248 238  
249   - // 重新加载 MbrUserDO 信息
250   - MbrUserDO user = userService.getUser(loginUser.getId());
  239 + // 重新加载 UserDO 信息
  240 + UserDO user = userService.getUser(loginUser.getId());
251 241 if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) {
252   - throw exception(AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面
  242 + // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面
  243 + throw exception(AUTH_TOKEN_EXPIRED);
253 244 }
254 245  
255 246 // 刷新 LoginUser 缓存
... ... @@ -258,8 +249,8 @@ public class SysAuthServiceImpl implements SysAuthService {
258 249  
259 250 @Override
260 251 public LoginUser mockLogin(Long userId) {
261   - // 获取用户编号对应的 MbrUserDO
262   - MbrUserDO user = userService.getUser(userId);
  252 + // 获取用户编号对应的 UserDO
  253 + UserDO user = userService.getUser(userId);
263 254 if (user == null) {
264 255 throw new UsernameNotFoundException(String.valueOf(userId));
265 256 }
... ... @@ -268,7 +259,7 @@ public class SysAuthServiceImpl implements SysAuthService {
268 259 this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS);
269 260  
270 261 // 创建 LoginUser 对象
271   - return SysAuthConvert.INSTANCE.convert(user);
  262 + return AuthConvert.INSTANCE.convert(user);
272 263 }
273 264  
274 265 @Override
... ... @@ -285,46 +276,35 @@ public class SysAuthServiceImpl implements SysAuthService {
285 276 }
286 277  
287 278 @Override
288   - public void updatePassword(Long userId, @Valid MbrAuthUpdatePasswordReqVO reqVO) {
  279 + public UserTypeEnum getUserType() {
  280 + return UserTypeEnum.MEMBER;
  281 + }
  282 +
  283 + @Override
  284 + public void updatePassword(Long userId, AppAuthUpdatePasswordReqVO reqVO) {
289 285 // 检验旧密码
290   - MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
  286 + UserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
291 287  
292 288 // 更新用户密码
293   - // TODO @宋天:不要更新整个对象哈
294   - userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
295   - userMapper.updateById(userDO);
  289 + UserDO mbrUserDO = UserDO.builder().id(userDO.getId())
  290 + .password(passwordEncoder.encode(reqVO.getPassword())).build();
  291 + userMapper.updateById(mbrUserDO);
296 292 }
297 293  
298 294 @Override
299   - public void resetPassword(MbrAuthResetPasswordReqVO reqVO) {
300   - // 根据验证码取出手机号,并查询用户
301   - String mobile = stringRedisTemplate.opsForValue().get(reqVO.getCode());
302   - MbrUserDO userDO = userMapper.selectByMobile(mobile);
303   - if (userDO == null){
304   - throw exception(USER_NOT_EXISTS);
305   - }
306   - // TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户
307   - // 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题
  295 + public void resetPassword(AppAuthResetPasswordReqVO reqVO) {
  296 + // 检验用户是否存在
  297 + UserDO userDO = checkUserIfExists(reqVO.getMobile());
308 298  
309   - // TODO @宋天:这块微信在讨论下哈~~~
310   -
311   - // 校验验证码
312   - smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
  299 + // 使用验证码
  300 + smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),
  301 + getClientIP());
313 302  
314 303 // 更新密码
315   - userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
316   - userMapper.updateById(userDO);
317   - }
318   -
319   - @Override
320   - public void checkIfMobileMatchCodeAndDeleteCode(String phone, String code) {
321   - // 检验用户手机与验证码是否匹配
322   - String mobile = stringRedisTemplate.opsForValue().get(code);
323   - if (!phone.equals(mobile)){
324   - throw exception(USER_CODE_FAILED);
325   - }
326   - // 销毁redis中此验证码
327   - stringRedisTemplate.delete(code);
  304 + UserDO mbrUserDO = UserDO.builder().build();
  305 + mbrUserDO.setId(userDO.getId());
  306 + mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
  307 + userMapper.updateById(mbrUserDO);
328 308 }
329 309  
330 310 /**
... ... @@ -332,11 +312,11 @@ public class SysAuthServiceImpl implements SysAuthService {
332 312 *
333 313 * @param id 用户 id
334 314 * @param oldPassword 旧密码
335   - * @return MbrUserDO 用户实体
  315 + * @return MemberUserDO 用户实体
336 316 */
337 317 @VisibleForTesting
338   - public MbrUserDO checkOldPassword(Long id, String oldPassword) {
339   - MbrUserDO user = userMapper.selectById(id);
  318 + public UserDO checkOldPassword(Long id, String oldPassword) {
  319 + UserDO user = userMapper.selectById(id);
340 320 if (user == null) {
341 321 throw exception(USER_NOT_EXISTS);
342 322 }
... ... @@ -347,12 +327,20 @@ public class SysAuthServiceImpl implements SysAuthService {
347 327 return user;
348 328 }
349 329  
  330 + public UserDO checkUserIfExists(String mobile) {
  331 + UserDO user = userMapper.selectByMobile(mobile);
  332 + if (user == null) {
  333 + throw exception(USER_NOT_EXISTS);
  334 + }
  335 + return user;
  336 + }
  337 +
350 338 private void createLogoutLog(Long userId, String username) {
351 339 SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
352 340 reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
353 341 reqDTO.setTraceId(TracerUtils.getTraceId());
354 342 reqDTO.setUserId(userId);
355   - reqDTO.setUserType(USER_TYPE_ENUM.getValue());
  343 + reqDTO.setUserType(getUserType().getValue());
356 344 reqDTO.setUsername(username);
357 345 reqDTO.setUserAgent(ServletUtils.getUserAgent());
358 346 reqDTO.setUserIp(getClientIP());
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/sms/SysSmsCodeService.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeService.java
1   -package cn.iocoder.yudao.userserver.modules.system.service.sms;
  1 +package cn.iocoder.yudao.module.member.service.sms;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.ServiceException;
4 4 import cn.iocoder.yudao.framework.common.validation.Mobile;
5   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
6   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
  5 +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO;
  6 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
7 7  
8 8 /**
9 9 * 短信验证码 Service 接口
... ... @@ -15,33 +15,37 @@ public interface SysSmsCodeService {
15 15 /**
16 16 * 创建短信验证码,并进行发送
17 17 *
18   - * @param mobile 手机号
19   - * @param scene 发送场景 {@link SysSmsSceneEnum}
  18 + * @param mobile 手机号
  19 + * @param scene 发送场景 {@link SysSmsSceneEnum}
20 20 * @param createIp 发送 IP
21 21 */
22 22 void sendSmsCode(@Mobile String mobile, Integer scene, String createIp);
23 23  
24 24 /**
25   - * 发送短信验证码,并检测手机号是否已被注册
26   - * @param reqVO 请求实体
27   - */
28   - void sendSmsNewCode(SysAuthSendSmsReqVO reqVO);
29   -
30   - /**
31 25 * 验证短信验证码,并进行使用
32 26 * 如果正确,则将验证码标记成已使用
33 27 * 如果错误,则抛出 {@link ServiceException} 异常
34 28 *
35 29 * @param mobile 手机号
36   - * @param scene 发送场景
37   - * @param code 验证码
  30 + * @param scene 发送场景
  31 + * @param code 验证码
38 32 * @param usedIp 使用 IP
39 33 */
40 34 void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp);
41 35  
42 36 /**
43 37 * 根据用户id发送验证码
  38 + *
44 39 * @param userId 用户id
45 40 */
46 41 void sendSmsCodeLogin(Long userId);
  42 +
  43 + /**
  44 + * 检查验证码是否有效
  45 + * @param mobile 手机
  46 + * @param code 验证码
  47 + * @param scene 使用场景
  48 + * @return 验证码记录
  49 + */
  50 + SysSmsCodeDO checkCodeIsExpired(String mobile, String code, Integer scene);
47 51 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/sms/impl/SysSmsCodeServiceImpl.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/sms/SysSmsCodeServiceImpl.java
1   -package cn.iocoder.yudao.userserver.modules.system.service.sms.impl;
  1 +package cn.iocoder.yudao.module.member.service.sms;
2 2  
3 3 import cn.hutool.core.map.MapUtil;
4   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
5 4 import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService;
6   -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
7   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
8   -import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
9   -import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper;
10   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
11   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsTemplateCodeConstants;
12   -import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties;
13   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
14   -import org.springframework.data.redis.core.StringRedisTemplate;
  5 +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
  6 +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO;
  7 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  8 +import cn.iocoder.yudao.module.member.dal.mysql.sms.SysSmsCodeMapper;
  9 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
  10 +import cn.iocoder.yudao.module.member.framework.sms.SmsCodeProperties;
  11 +import cn.iocoder.yudao.module.member.service.user.UserService;
15 12 import org.springframework.stereotype.Service;
16 13 import org.springframework.validation.annotation.Validated;
17 14  
18 15 import javax.annotation.Resource;
19 16 import java.util.Date;
20   -import java.util.concurrent.TimeUnit;
21 17  
22 18 import static cn.hutool.core.util.RandomUtil.randomInt;
23   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 19 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
25   -import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*;
  20 +import static cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants.*;
26 21  
27 22 /**
28 23 * 短信验证码 Service 实现类
... ... @@ -33,11 +28,6 @@ import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConst
33 28 @Validated
34 29 public class SysSmsCodeServiceImpl implements SysSmsCodeService {
35 30  
36   - /**
37   - * 验证码 + 手机 在redis中存储的有效时间,单位:分钟
38   - */
39   - private static final Long CODE_TIME = 10L;
40   -
41 31 @Resource
42 32 private SmsCodeProperties smsCodeProperties;
43 33  
... ... @@ -45,52 +35,50 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
45 35 private SysSmsCodeMapper smsCodeMapper;
46 36  
47 37 @Resource
48   - private MbrUserService mbrUserService;
  38 + private UserService userService;
49 39  
50 40 @Resource
51 41 private SysSmsCoreService smsCoreService;
52 42  
53   - @Resource
54   - private StringRedisTemplate stringRedisTemplate;
55   -
56 43 @Override
57 44 public void sendSmsCode(String mobile, Integer scene, String createIp) {
58 45 // 创建验证码
59 46 String code = this.createSmsCode(mobile, scene, createIp);
  47 +
  48 + // 获取发送模板
  49 + String codeTemplate = SysSmsSceneEnum.getCodeByScene(scene);
  50 +
  51 + // 如果是更换手机号发送验证码,则需要检测手机号是否被注册
  52 + if (SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene().equals(scene)){
  53 + this.checkMobileIsRegister(mobile,scene);
  54 + }
  55 +
60 56 // 发送验证码
61   - // TODO @宋天:这里可以拓展下 SysSmsSceneEnum,支持设置对应的短信模板编号(不同场景的短信文案是不同的)、是否要校验手机号已经注册。这样 Controller 就可以收口成一个接口了。相当于说,不同场景,不同策略
62   - smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN,
  57 + smsCoreService.sendSingleSmsToMember(mobile, null, codeTemplate,
63 58 MapUtil.of("code", code));
64   -
65   - // 存储手机号与验证码到redis,用于标记
66   - // TODO @宋天:SysSmsCodeDO 表应该足够,无需增加额外的 redis 存储哇
67   - // TODO @宋天:Redis 相关的操作,不要散落到业务层,而是写一个它对应的 RedisDAO。这样,实现业务与技术的解耦
68   - // TODO @宋天:直接使用 code 作为 key,会存在 2 个问题:1)code 可能会冲突,多个手机号之间;2)缺少前缀。例如说 sms_code_${code}
69   - stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES);
70 59 }
71 60  
72   - @Override
73   - public void sendSmsNewCode(SysAuthSendSmsReqVO reqVO) {
  61 + public void checkMobileIsRegister(String mobile, Integer scene) {
74 62 // 检测手机号是否已被使用
75   - MbrUserDO userByMobile = mbrUserService.getUserByMobile(reqVO.getMobile());
76   - if (userByMobile != null){
77   - throw exception(USER_SMS_CODE_IS_EXISTS);
  63 + UserDO user = userService.getUserByMobile(mobile);
  64 + if (user != null) {
  65 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_IS_EXISTS);
78 66 }
79 67  
80 68 // 发送短信
81   - this.sendSmsCode(reqVO.getMobile(),reqVO.getScene(),getClientIP());
  69 + this.sendSmsCode(mobile,scene,getClientIP());
82 70 }
83 71  
84 72 private String createSmsCode(String mobile, Integer scene, String ip) {
85 73 // 校验是否可以发送验证码,不用筛选场景
86   - SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null);
  74 + SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null,null);
87 75 if (lastSmsCode != null) {
88 76 if (lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。
89   - throw exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
  77 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
90 78 }
91 79 if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime()
92 80 < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁
93   - throw exception(USER_SMS_CODE_SEND_TOO_FAST);
  81 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_SEND_TOO_FAST);
94 82 }
95 83 // TODO 芋艿:提升,每个 IP 每天可发送数量
96 84 // TODO 芋艿:提升,每个 IP 每小时可发送数量
... ... @@ -107,20 +95,12 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
107 95  
108 96 @Override
109 97 public void useSmsCode(String mobile, Integer scene, String code, String usedIp) {
110   - // 校验验证码
111   - SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, scene);
112   - if (lastSmsCode == null) { // 若验证码不存在,抛出异常
113   - throw exception(USER_SMS_CODE_NOT_FOUND);
114   - }
115   - if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime()
116   - >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
117   - throw exception(USER_SMS_CODE_EXPIRED);
118   - }
119   - if (lastSmsCode.getUsed()) { // 验证码已使用
120   - throw exception(USER_SMS_CODE_USED);
121   - }
122   - if (!lastSmsCode.getCode().equals(code)) {
123   - throw exception(USER_SMS_CODE_NOT_CORRECT);
  98 + // 检测验证码是否有效
  99 + SysSmsCodeDO lastSmsCode = this.checkCodeIsExpired(mobile, code, scene);
  100 +
  101 + // 判断验证码是否已被使用
  102 + if (Boolean.TRUE.equals(lastSmsCode.getUsed())) {
  103 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_USED);
124 104 }
125 105  
126 106 // 使用验证码
... ... @@ -130,12 +110,28 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
130 110  
131 111 @Override
132 112 public void sendSmsCodeLogin(Long userId) {
133   - MbrUserDO user = mbrUserService.getUser(userId);
  113 + UserDO user = userService.getUser(userId);
134 114 if (user == null){
135   - throw exception(USER_NOT_EXISTS);
  115 + throw ServiceExceptionUtil.exception(USER_NOT_EXISTS);
136 116 }
137 117 // 发送验证码
138 118 this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP());
139 119 }
140 120  
  121 + @Override
  122 + public SysSmsCodeDO checkCodeIsExpired(String mobile, String code, Integer scene) {
  123 + // 校验验证码
  124 + SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile,code,scene);
  125 +
  126 + // 若验证码不存在,抛出异常
  127 + if (lastSmsCode == null) {
  128 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_NOT_FOUND);
  129 + }
  130 + if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime()
  131 + >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
  132 + throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXPIRED);
  133 + }
  134 + return lastSmsCode;
  135 + }
  136 +
141 137 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserService.java
1   -package cn.iocoder.yudao.userserver.modules.member.service.user;
  1 +package cn.iocoder.yudao.module.member.service.user;
2 2  
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
5 3 import cn.iocoder.yudao.framework.common.validation.Mobile;
6   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
  4 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
  5 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
  6 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
7 7  
8 8 import java.io.InputStream;
9 9  
10 10 /**
11   - * 前台用户 Service 接口
  11 + * 会员用户 Service 接口
12 12 *
13 13 * @author 芋道源码
14 14 */
15   -public interface MbrUserService {
  15 +public interface UserService {
16 16  
17 17 /**
18 18 * 通过手机查询用户
... ... @@ -20,7 +20,7 @@ public interface MbrUserService {
20 20 * @param mobile 手机
21 21 * @return 用户对象
22 22 */
23   - MbrUserDO getUserByMobile(String mobile);
  23 + UserDO getUserByMobile(String mobile);
24 24  
25 25 /**
26 26 * 基于手机号创建用户。
... ... @@ -30,7 +30,7 @@ public interface MbrUserService {
30 30 * @param registerIp 注册 IP
31 31 * @return 用户对象
32 32 */
33   - MbrUserDO createUserIfAbsent(@Mobile String mobile, String registerIp);
  33 + UserDO createUserIfAbsent(@Mobile String mobile, String registerIp);
34 34  
35 35 /**
36 36 * 更新用户的最后登陆信息
... ... @@ -46,14 +46,14 @@ public interface MbrUserService {
46 46 * @param id 用户ID
47 47 * @return 用户对象信息
48 48 */
49   - MbrUserDO getUser(Long id);
  49 + UserDO getUser(Long id);
50 50  
51 51 /**
52 52 * 修改用户昵称
53 53 * @param userId 用户id
54 54 * @param nickname 用户新昵称
55 55 */
56   - void updateNickname(Long userId, String nickname);
  56 + void updateUserNickname(Long userId, String nickname);
57 57  
58 58 /**
59 59 * 修改用户头像
... ... @@ -61,21 +61,13 @@ public interface MbrUserService {
61 61 * @param inputStream 头像文件
62 62 * @return 头像url
63 63 */
64   - String updateAvatar(Long userId, InputStream inputStream);
65   -
66   - /**
67   - * 根据用户id,获取用户头像与昵称
68   - *
69   - * @param userId 用户id
70   - * @return 用户响应实体类
71   - */
72   - MbrUserInfoRespVO getUserInfo(Long userId);
  64 + String updateUserAvatar(Long userId, InputStream inputStream);
73 65  
74 66 /**
75 67 * 修改手机
76 68 * @param userId 用户id
77 69 * @param reqVO 请求实体
78 70 */
79   - void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO);
  71 + void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO);
80 72  
81 73 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java renamed to yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/user/UserServiceImpl.java
1   -package cn.iocoder.yudao.userserver.modules.member.service.user.impl;
  1 +package cn.iocoder.yudao.module.member.service.user;
2 2  
3 3 import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.IdUtil;
5 5 import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
6   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
7   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
8 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
9   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
10   -import cn.iocoder.yudao.userserver.modules.member.convert.user.UserProfileConvert;
11   -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
12   -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
13   -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
  7 +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
  8 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO;
  10 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  11 +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper;
  12 +import cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants;
  13 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
  14 +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
14 15 import com.google.common.annotations.VisibleForTesting;
15 16 import lombok.extern.slf4j.Slf4j;
16 17 import org.springframework.security.crypto.password.PasswordEncoder;
17 18 import org.springframework.stereotype.Service;
  19 +import org.springframework.transaction.annotation.Transactional;
18 20  
19 21 import javax.annotation.Resource;
20 22 import javax.validation.Valid;
... ... @@ -22,39 +24,39 @@ import java.io.InputStream;
22 24 import java.util.Date;
23 25  
24 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25   -import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.USER_NOT_EXISTS;
  27 +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
  28 +import static cn.iocoder.yudao.module.member.enums.MemberErrorCodeConstants.USER_NOT_EXISTS;
26 29  
27 30 /**
28   - * User Service 实现类
  31 + * 会员 User Service 实现类
29 32 *
30 33 * @author 芋道源码
31 34 */
32 35 @Service
33 36 @Valid
34 37 @Slf4j
35   -public class MbrUserServiceImpl implements MbrUserService {
  38 +public class UserServiceImpl implements UserService {
36 39  
37 40 @Resource
38   - private MbrUserMapper userMapper;
  41 + private UserMapper memberUserMapper;
39 42  
40 43 @Resource
41 44 private InfFileCoreService fileCoreService;
42   -
43 45 @Resource
44   - private PasswordEncoder passwordEncoder;
  46 + private SysSmsCodeService smsCodeService;
45 47  
46 48 @Resource
47   - private SysAuthService sysAuthService;
  49 + private PasswordEncoder passwordEncoder;
48 50  
49 51 @Override
50   - public MbrUserDO getUserByMobile(String mobile) {
51   - return userMapper.selectByMobile(mobile);
  52 + public UserDO getUserByMobile(String mobile) {
  53 + return memberUserMapper.selectByMobile(mobile);
52 54 }
53 55  
54 56 @Override
55   - public MbrUserDO createUserIfAbsent(String mobile, String registerIp) {
  57 + public UserDO createUserIfAbsent(String mobile, String registerIp) {
56 58 // 用户已经存在
57   - MbrUserDO user = userMapper.selectByMobile(mobile);
  59 + UserDO user = memberUserMapper.selectByMobile(mobile);
58 60 if (user != null) {
59 61 return user;
60 62 }
... ... @@ -62,86 +64,84 @@ public class MbrUserServiceImpl implements MbrUserService {
62 64 return this.createUser(mobile, registerIp);
63 65 }
64 66  
65   - private MbrUserDO createUser(String mobile, String registerIp) {
  67 + private UserDO createUser(String mobile, String registerIp) {
66 68 // 生成密码
67 69 String password = IdUtil.fastSimpleUUID();
68 70 // 插入用户
69   - MbrUserDO user = new MbrUserDO();
  71 + UserDO user = new UserDO();
70 72 user.setMobile(mobile);
71 73 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
72 74 user.setPassword(passwordEncoder.encode(password)); // 加密密码
73 75 user.setRegisterIp(registerIp);
74   - userMapper.insert(user);
  76 + memberUserMapper.insert(user);
75 77 return user;
76 78 }
77 79  
78 80 @Override
79 81 public void updateUserLogin(Long id, String loginIp) {
80   - userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date()));
  82 + memberUserMapper.updateById(new UserDO().setId(id)
  83 + .setLoginIp(loginIp).setLoginDate(new Date()));
81 84 }
82 85  
83 86 @Override
84   - public MbrUserDO getUser(Long id) {
85   - return userMapper.selectById(id);
  87 + public UserDO getUser(Long id) {
  88 + return memberUserMapper.selectById(id);
86 89 }
87 90  
88 91 @Override
89   - public void updateNickname(Long userId, String nickname) {
90   - MbrUserDO user = this.checkUserExists(userId);
  92 + public void updateUserNickname(Long userId, String nickname) {
  93 + UserDO user = this.checkUserExists(userId);
91 94 // 仅当新昵称不等于旧昵称时进行修改
92 95 if (nickname.equals(user.getNickname())){
93 96 return;
94 97 }
95   - MbrUserDO userDO = new MbrUserDO();
  98 + UserDO userDO = new UserDO();
96 99 userDO.setId(user.getId());
97 100 userDO.setNickname(nickname);
98   - userMapper.updateById(userDO);
  101 + memberUserMapper.updateById(userDO);
99 102 }
100 103  
101 104 @Override
102   - public String updateAvatar(Long userId, InputStream avatarFile) {
  105 + public String updateUserAvatar(Long userId, InputStream avatarFile) {
103 106 this.checkUserExists(userId);
104 107 // 创建文件
105 108 String avatar = fileCoreService.createFile(IdUtil.fastUUID(), IoUtil.readBytes(avatarFile));
106 109 // 更新头像路径
107   - MbrUserDO userDO = MbrUserDO.builder()
108   - .id(userId)
109   - .avatar(avatar)
110   - .build();
111   - userMapper.updateById(userDO);
  110 + memberUserMapper.updateById(UserDO.builder().id(userId).avatar(avatar).build());
112 111 return avatar;
113 112 }
114 113  
115   - @Override
116   - public MbrUserInfoRespVO getUserInfo(Long userId) {
117   - MbrUserDO user = this.checkUserExists(userId);
118   - // 拼接返回结果
119   - return UserProfileConvert.INSTANCE.convert(user);
120   - }
121   -
122   - @Override
123   - public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) {
  114 + @Transactional(rollbackFor = Exception.class)
  115 + public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) {
124 116 // 检测用户是否存在
125   - MbrUserDO userDO = checkUserExists(userId);
126   - // 检测手机与验证码是否匹配
127   - // TODO @宋天:修改手机的时候。应该要校验,老手机 + 老手机 code;新手机 + 新手机 code
128   - sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode());
  117 + checkUserExists(userId);
  118 +
  119 + // 校验旧手机和旧验证码
  120 + SysSmsCodeDO sysSmsCodeDO = smsCodeService.checkCodeIsExpired(reqVO.getOldMobile(), reqVO.getOldCode(),
  121 + SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
  122 + // 判断旧 code 是否未被使用,如果是,抛出异常
  123 + if (Boolean.FALSE.equals(sysSmsCodeDO.getUsed())){
  124 + throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED);
  125 + }
  126 +
  127 + // 使用新验证码
  128 + smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),
  129 + reqVO.getCode(),getClientIP());
  130 +
129 131 // 更新用户手机
130   - // TODO @宋天:更新的时候,单独创建对象。直接全量更新,会可能导致属性覆盖。可以看看打印出来的 SQL 哈
131   - userDO.setMobile(reqVO.getMobile());
132   - userMapper.updateById(userDO);
  132 + memberUserMapper.updateById(UserDO.builder().id(userId).mobile(reqVO.getMobile()).build());
133 133 }
134 134  
135 135 @VisibleForTesting
136   - public MbrUserDO checkUserExists(Long id) {
  136 + public UserDO checkUserExists(Long id) {
137 137 if (id == null) {
138 138 return null;
139 139 }
140   - MbrUserDO user = userMapper.selectById(id);
  140 + UserDO user = memberUserMapper.selectById(id);
141 141 if (user == null) {
142 142 throw exception(USER_NOT_EXISTS);
143   - }else{
144   - return user;
145 143 }
  144 + return user;
146 145 }
  146 +
147 147 }
... ...
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/system/service/SysAuthServiceTest.java renamed to yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/auth/SysAuthServiceTest.java
1   -package cn.iocoder.yudao.userserver.modules.system.service;
  1 +package cn.iocoder.yudao.module.member.service.auth;
2 2  
3   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
4 3 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
5 4 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
6 5 import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService;
7 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 7 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
9 8 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
10   -import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
11   -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
12   -import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
13   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO;
14   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthUpdatePasswordReqVO;
15   -import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
16   -import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
17   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
  9 +import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthResetPasswordReqVO;
  10 +import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswordReqVO;
  11 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  12 +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper;
  13 +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
  14 +import cn.iocoder.yudao.module.member.service.user.UserService;
  15 +import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest;
18 16 import org.junit.jupiter.api.Test;
19 17 import org.springframework.boot.test.mock.mockito.MockBean;
20 18 import org.springframework.context.annotation.Import;
... ... @@ -23,7 +21,6 @@ import org.springframework.security.authentication.AuthenticationManager;
23 21 import org.springframework.security.crypto.password.PasswordEncoder;
24 22  
25 23 import javax.annotation.Resource;
26   -import java.util.concurrent.TimeUnit;
27 24 import java.util.function.Consumer;
28 25  
29 26 import static cn.hutool.core.util.RandomUtil.randomEle;
... ... @@ -35,17 +32,17 @@ import static org.mockito.Mockito.when;
35 32  
36 33 // TODO @芋艿:单测的 review,等逻辑都达成一致后
37 34 /**
38   - * {@link SysAuthService} 的单元测试类
  35 + * {@link AuthService} 的单元测试类
39 36 *
40 37 * @author 宋天
41 38 */
42   -@Import({SysAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
  39 +@Import({AuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
43 40 public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
44 41  
45 42 @MockBean
46 43 private AuthenticationManager authenticationManager;
47 44 @MockBean
48   - private MbrUserService userService;
  45 + private UserService userService;
49 46 @MockBean
50 47 private SysSmsCodeService smsCodeService;
51 48 @MockBean
... ... @@ -59,21 +56,21 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
59 56 @MockBean
60 57 private PasswordEncoder passwordEncoder;
61 58 @Resource
62   - private MbrUserMapper mbrUserMapper;
  59 + private UserMapper mbrUserMapper;
63 60 @Resource
64   - private SysAuthServiceImpl authService;
  61 + private AuthServiceImpl authService;
65 62  
66 63 @Test
67 64 public void testUpdatePassword_success(){
68 65 // 准备参数
69   - MbrUserDO userDO = randomMbrUserDO();
  66 + UserDO userDO = randomUserDO();
70 67 mbrUserMapper.insert(userDO);
71 68  
72 69 // 新密码
73 70 String newPassword = randomString();
74 71  
75 72 // 请求实体
76   - MbrAuthUpdatePasswordReqVO reqVO = MbrAuthUpdatePasswordReqVO.builder()
  73 + AppAuthUpdatePasswordReqVO reqVO = AppAuthUpdatePasswordReqVO.builder()
77 74 .oldPassword(userDO.getPassword())
78 75 .password(newPassword)
79 76 .build();
... ... @@ -84,14 +81,14 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
84 81 when(passwordEncoder.encode(newPassword)).thenReturn(newPassword);
85 82  
86 83 // 更新用户密码
87   - authService.updatePassword(userDO.getId(),reqVO);
  84 + authService.updatePassword(userDO.getId(), reqVO);
88 85 assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),newPassword);
89 86 }
90 87  
91 88 @Test
92 89 public void testResetPassword_success(){
93 90 // 准备参数
94   - MbrUserDO userDO = randomMbrUserDO();
  91 + UserDO userDO = randomUserDO();
95 92 mbrUserMapper.insert(userDO);
96 93  
97 94 // 随机密码
... ... @@ -99,17 +96,15 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
99 96 // 随机验证码
100 97 String code = randomNumbers(4);
101 98  
102   - MbrAuthResetPasswordReqVO reqVO = MbrAuthResetPasswordReqVO.builder()
103   - .password(password)
104   - .code(code)
105   - .build();
106   - // 放入code+手机号
107   - stringRedisTemplate.opsForValue().set(code,userDO.getMobile(),10, TimeUnit.MINUTES);
108   -
109 99 // mock
110 100 when(passwordEncoder.encode(password)).thenReturn(password);
111 101  
112 102 // 更新用户密码
  103 + AppAuthResetPasswordReqVO reqVO = new AppAuthResetPasswordReqVO();
  104 + reqVO.setMobile(userDO.getMobile());
  105 + reqVO.setPassword(password);
  106 + reqVO.setCode(code);
  107 +
113 108 authService.resetPassword(reqVO);
114 109 assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password);
115 110 }
... ... @@ -118,12 +113,12 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
118 113 // ========== 随机对象 ==========
119 114  
120 115 @SafeVarargs
121   - private static MbrUserDO randomMbrUserDO(Consumer<MbrUserDO>... consumers) {
122   - Consumer<MbrUserDO> consumer = (o) -> {
  116 + private static UserDO randomUserDO(Consumer<UserDO>... consumers) {
  117 + Consumer<UserDO> consumer = (o) -> {
123 118 o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
124 119 o.setPassword(randomString());
125 120 };
126   - return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers));
  121 + return randomPojo(UserDO.class, ArrayUtils.append(consumer, consumers));
127 122 }
128 123  
129 124  
... ...
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java renamed to yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/service/user/MbrUserServiceImplTest.java
1   -package cn.iocoder.yudao.userserver.modules.member.service;
  1 +package cn.iocoder.yudao.module.member.service.user;
2 2  
  3 +import cn.hutool.core.util.RandomUtil;
3 4 import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
4   -import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 7 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
8   -import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
9   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
10   -import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
11   -import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
12   -import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl;
13   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
14   -import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
15   -import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
16   -import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
  8 +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
  9 +import cn.iocoder.yudao.module.member.dal.dataobject.sms.SysSmsCodeDO;
  10 +import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
  11 +import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper;
  12 +import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
  13 +import cn.iocoder.yudao.module.member.service.auth.AuthServiceImpl;
  14 +import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
  15 +import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest;
17 16 import org.junit.jupiter.api.Test;
18 17 import org.springframework.boot.test.mock.mockito.MockBean;
19 18 import org.springframework.context.annotation.Import;
... ... @@ -32,24 +31,24 @@ import static org.mockito.Mockito.*;
32 31  
33 32 // TODO @芋艿:单测的 review,等逻辑都达成一致后
34 33 /**
35   - * {@link MbrUserServiceImpl} 的单元测试类
  34 + * {@link UserServiceImpl} 的单元测试类
36 35 *
37 36 * @author 宋天
38 37 */
39   -@Import({MbrUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
  38 +@Import({UserServiceImpl.class, YudaoRedisAutoConfiguration.class})
40 39 public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
41 40  
42 41 @Resource
43   - private MbrUserServiceImpl mbrUserService;
  42 + private UserServiceImpl mbrUserService;
44 43  
45 44 @Resource
46 45 private StringRedisTemplate stringRedisTemplate;
47 46  
48 47 @Resource
49   - private MbrUserMapper userMapper;
  48 + private UserMapper userMapper;
50 49  
51 50 @MockBean
52   - private SysAuthServiceImpl authService;
  51 + private AuthServiceImpl authService;
53 52  
54 53 @MockBean
55 54 private InfFileCoreService fileCoreService;
... ... @@ -63,14 +62,14 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
63 62 @Test
64 63 public void testUpdateNickName_success(){
65 64 // mock 数据
66   - MbrUserDO userDO = randomMbrUserDO();
  65 + UserDO userDO = randomUserDO();
67 66 userMapper.insert(userDO);
68 67  
69 68 // 随机昵称
70 69 String newNickName = randomString();
71 70  
72 71 // 调用接口修改昵称
73   - mbrUserService.updateNickname(userDO.getId(),newNickName);
  72 + mbrUserService.updateUserNickname(userDO.getId(),newNickName);
74 73 // 查询新修改后的昵称
75 74 String nickname = mbrUserService.getUser(userDO.getId()).getNickname();
76 75 // 断言
... ... @@ -78,20 +77,9 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
78 77 }
79 78  
80 79 @Test
81   - public void testGetUserInfo_success(){
82   - // mock 数据
83   - MbrUserDO userDO = randomMbrUserDO();
84   - userMapper.insert(userDO);
85   -
86   - // 查询用户昵称与头像
87   - MbrUserInfoRespVO userInfo = mbrUserService.getUserInfo(userDO.getId());
88   - System.out.println(userInfo);
89   - }
90   -
91   - @Test
92 80 public void testUpdateAvatar_success(){
93 81 // mock 数据
94   - MbrUserDO dbUser = randomMbrUserDO();
  82 + UserDO dbUser = randomUserDO();
95 83 userMapper.insert(dbUser);
96 84  
97 85 // 准备参数
... ... @@ -102,7 +90,7 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
102 90 String avatar = randomString();
103 91 when(fileCoreService.createFile(anyString(), eq(avatarFileBytes))).thenReturn(avatar);
104 92 // 调用
105   - String str = mbrUserService.updateAvatar(userId, avatarFile);
  93 + String str = mbrUserService.updateUserAvatar(userId, avatarFile);
106 94 // 断言
107 95 assertEquals(avatar, str);
108 96 }
... ... @@ -111,28 +99,28 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
111 99 public void updateMobile_success(){
112 100 // mock数据
113 101 String oldMobile = randomNumbers(11);
114   - MbrUserDO userDO = randomMbrUserDO();
  102 + UserDO userDO = randomUserDO();
115 103 userDO.setMobile(oldMobile);
116 104 userMapper.insert(userDO);
117 105  
118   - // 验证旧手机
119   - sysSmsCodeService.sendSmsCodeLogin(userDO.getId());
120   -
121   - // 验证旧手机验证码是否正确
122   - sysSmsCodeService.useSmsCode(oldMobile,SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),"123","1.1.1.1");
123   - // 验证新手机
124   - SysAuthSendSmsReqVO smsReqVO = new SysAuthSendSmsReqVO();
125   - smsReqVO.setMobile(oldMobile);
126   - smsReqVO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
127   - sysSmsCodeService.sendSmsNewCode(smsReqVO);
  106 + // 旧手机和旧验证码
  107 + SysSmsCodeDO codeDO = new SysSmsCodeDO();
  108 + String oldCode = RandomUtil.randomString(4);
  109 + codeDO.setMobile(userDO.getMobile());
  110 + codeDO.setCode(oldCode);
  111 + codeDO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
  112 + codeDO.setUsed(Boolean.FALSE);
  113 + when(sysSmsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
128 114  
129 115 // 更新手机号
130 116 String newMobile = randomNumbers(11);
131   - String code = randomNumbers(4);
132   - MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO();
  117 + String newCode = randomNumbers(4);
  118 + AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO();
133 119 reqVO.setMobile(newMobile);
134   - reqVO.setCode(code);
135   - mbrUserService.updateMobile(userDO.getId(),reqVO);
  120 + reqVO.setCode(newCode);
  121 + reqVO.setOldMobile(oldMobile);
  122 + reqVO.setOldCode(oldCode);
  123 + mbrUserService.updateUserMobile(userDO.getId(),reqVO);
136 124  
137 125 assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile);
138 126 }
... ... @@ -140,11 +128,11 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
140 128 // ========== 随机对象 ==========
141 129  
142 130 @SafeVarargs
143   - private static MbrUserDO randomMbrUserDO(Consumer<MbrUserDO>... consumers) {
144   - Consumer<MbrUserDO> consumer = (o) -> {
  131 + private static UserDO randomUserDO(Consumer<UserDO>... consumers) {
  132 + Consumer<UserDO> consumer = (o) -> {
145 133 o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
146 134 };
147   - return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers));
  135 + return randomPojo(UserDO.class, ArrayUtils.append(consumer, consumers));
148 136 }
149 137  
150 138 }
... ...
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbAndRedisUnitTest.java renamed to yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbAndRedisUnitTest.java
1   -package cn.iocoder.yudao.userserver;
  1 +package cn.iocoder.yudao.module.member.test;
2 2  
3 3 import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
4 4 import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
5 5 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
6   -import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;
7 6 import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
8 7 import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
9 8 import org.redisson.spring.starter.RedissonAutoConfiguration;
... ...
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbUnitTest.java renamed to yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/BaseDbUnitTest.java
1   -package cn.iocoder.yudao.userserver;
  1 +package cn.iocoder.yudao.module.member.test;
2 2  
3 3 import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
4 4 import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
... ...
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/config/RedisTestConfiguration.java renamed to yudao-module-member/yudao-module-member-impl/src/test/java/cn/iocoder/yudao/module/member/test/RedisTestConfiguration.java
1   -package cn.iocoder.yudao.userserver.config;
  1 +package cn.iocoder.yudao.module.member.test;
2 2  
3 3 import com.github.fppt.jedismock.RedisServer;
4 4 import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
... ...
yudao-user-server/src/test/resources/application-unit-test.yaml renamed to yudao-module-member/yudao-module-member-impl/src/test/resources/application-unit-test.yaml
... ... @@ -42,3 +42,8 @@ mybatis:
42 42 --- #################### 芋道相关配置 ####################
43 43  
44 44 # 芋道配置项,设置当前项目所有自定义的配置
  45 +yudao:
  46 + info:
  47 + base-package: cn.iocoder.yudao.module.member.dal.mysql
  48 + core-service:
  49 + base-package: cn.iocoder.yudao.module.member.dal.mysql # TODO 芋艿:要清理掉
... ...
yudao-user-server/src/test/resources/file/erweima.jpg renamed to yudao-module-member/yudao-module-member-impl/src/test/resources/file/erweima.jpg

18 KB

yudao-user-server/src/test/resources/logback-spring.xml renamed to yudao-module-member/yudao-module-member-impl/src/test/resources/logback-spring.xml
yudao-user-server/src/test/resources/sql/clean.sql renamed to yudao-module-member/yudao-module-member-impl/src/test/resources/sql/clean.sql
yudao-user-server/src/test/resources/sql/create_tables.sql renamed to yudao-module-member/yudao-module-member-impl/src/test/resources/sql/create_tables.sql
yudao-user-server/pom.xml
... ... @@ -90,15 +90,6 @@
90 90 <artifactId>yudao-spring-boot-starter-test</artifactId>
91 91 <scope>test</scope>
92 92 </dependency>
93   -
94   - <!-- TODO @宋天:junit 已经在 yudao-spring-boot-starter-test 啦,不用在引入哈 -->
95   - <!--单元测试相关-->
96   - <dependency>
97   - <groupId>junit</groupId>
98   - <artifactId>junit</artifactId>
99   - <scope>test</scope>
100   - </dependency>
101   -
102 93 <!-- 工具类相关 -->
103 94  
104 95 </dependencies>
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java deleted
1   -package cn.iocoder.yudao.userserver.framework.security;
2   -
3   -import cn.iocoder.yudao.framework.web.config.WebProperties;
4   -import org.springframework.context.annotation.Bean;
5   -import org.springframework.context.annotation.Configuration;
6   -import org.springframework.security.config.Customizer;
7   -import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8   -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
9   -
10   -import javax.annotation.Resource;
11   -
12   -@Configuration
13   -public class SecurityConfiguration {
14   -
15   - @Resource
16   - private WebProperties webProperties;
17   -
18   - @Bean
19   - public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
20   - return registry -> {
21   - registry.antMatchers(api("/**")).permitAll(); // 默认 API 都是用户可访问
22   - };
23   - }
24   -
25   - private String api(String url) {
26   - return webProperties.getApiPrefix() + url;
27   - }
28   -
29   -}