From ee3ce43c8e0b9e5ffc9ab98533ffa9a88b0ccfaa Mon Sep 17 00:00:00 2001 From: liulujian Date: Tue, 28 Apr 2026 18:06:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plans/2026-04-28-修改密码功能实现计划.md | 367 ++++++++++++++++++ .../specs/2026-04-28-修改密码功能设计.md | 147 +++++++ txw-mhzc-web/src/pages/index/api/login.js | 10 + txw-mhzc-web/src/pages/index/router/routes.js | 6 + .../src/pages/index/views/glxtSy/config.js | 5 + .../views/gzt/components/AccountShortcuts.vue | 2 +- .../index/views/yhzx/zhanghugl/index.vue | 192 +++++++++ .../java/com/css/txw/mhzc/api/IMhzcApi.java | 36 +- .../com/css/txw/mhzc/pojo/YhxxReqDTO.java | 2 + .../txw/mhzc/controller/UserController.java | 14 +- .../txw/mhzc/service/TxwMhzcYhxxbService.java | 8 +- .../service/impl/TxwMhzcYhxxbServiceImpl.java | 18 +- .../com/css/txw/sso/api/yhxx/YhxxApi.java | 18 - .../com/css/txw/sso/api/yhxx/YhxxApi.class | Bin 820 -> 0 bytes .../txw/sso/constants/ErrorCodeConstants.java | 5 + .../css/txw/sso/constants/SsoConstants.java | 2 +- .../sso/controller/auth/AuthController.java | 16 + .../txw/sso/pojo/vo/ChangePasswordReqVO.java | 29 ++ .../css/txw/sso/service/auth/AuthService.java | 16 + .../service/auth/impl/AuthServiceImpl.java | 70 ++++ .../css/txw/sso/service/yhxx/YhxxService.java | 6 +- .../service/yhxx/impl/YhxxServiceImpl.java | 17 + txw-yygl-web/src/pages/index/api/htgl.js | 4 +- 23 files changed, 944 insertions(+), 46 deletions(-) create mode 100644 docs/superpowers/plans/2026-04-28-修改密码功能实现计划.md create mode 100644 docs/superpowers/specs/2026-04-28-修改密码功能设计.md create mode 100644 txw-mhzc-web/src/pages/index/views/yhzx/zhanghugl/index.vue delete mode 100644 txw-sso/txw-sso-service-api/src/main/java/com/css/txw/sso/api/yhxx/YhxxApi.java delete mode 100644 txw-sso/txw-sso-service-api/target/classes/com/css/txw/sso/api/yhxx/YhxxApi.class create mode 100644 txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/pojo/vo/ChangePasswordReqVO.java diff --git a/docs/superpowers/plans/2026-04-28-修改密码功能实现计划.md b/docs/superpowers/plans/2026-04-28-修改密码功能实现计划.md new file mode 100644 index 0000000..ec55532 --- /dev/null +++ b/docs/superpowers/plans/2026-04-28-修改密码功能实现计划.md @@ -0,0 +1,367 @@ +# 修改密码功能实现计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 为碳信网平台添加普通用户自助修改密码功能(txw-sso后端 + txw-mhzc-web前端) + +**Architecture:** +- 后端:SSO服务新增 `POST /sso/auth/changePassword` 接口,用户通过 authenticate 验证旧密码,通过 mhzc-service 的 Feign 接口更新用户密码 +- 前端:mhzc-web 新增修改密码页面(账号管理),工作台增加快捷入口,用户中心左侧菜单增加"账号管理"菜单项 + +**Tech Stack:** Java Spring Boot / Vue 2 / TDesign / Feign + +--- + +## 涉及的变更文件 + +### 后端(txw-sso) +| 文件 | 改动 | +|------|------| +| `AuthService.java` | 新增 `changePassword` 接口声明 | +| `AuthServiceImpl.java` | 实现 `changePassword` 逻辑 | +| `AuthController.java` | 新增 `/auth/changePassword` 路由 | +| `ChangePasswordReqVO.java` | 新建请求 VO | +| `ChangePasswordRespVO.java` | 新建响应 VO | +| `YhxxApi.java` (txw-sso-api) | 新增 Feign 方法 `updatePassword` | +| `TxwMhzcYhxxbService.java` (txw-mhzc) | 新增 `updatePassword` 方法声明 | +| `TxwMhzcYhxxbServiceImpl.java` (txw-mhzc) | 实现 `updatePassword` | +| `TxwMhzcYhxxbMapper.xml` | 新增 updatePassword SQL | +| `ISsoApi.java` | FeignClient name 常量(需确认mhzc服务名) | + +### 前端(txw-mhzc-web) +| 文件 | 改动 | +|------|------| +| `views/gzt/index.vue` | 新增修改密码快捷入口按钮 | +| `views/yhzx/zhanghugl/index.vue` | 新建修改密码页面 | +| `router/routes.js` | 新增 `zhanghugl` 路由 | +| `views/glxtSy/config.js` | 菜单配置新增"账号管理" | +| `api/sso.js` | 新建,封装 changePassword API | + +--- + +## 后端任务拆分 + +### Task 1: 后端 - 新建 ChangePasswordReqVO + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/pojo/vo/ChangePasswordReqVO.java` + +- [ ] **Step 1: 创建文件** + +```java +package com.css.txw.sso.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Schema(description = "修改密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChangePasswordReqVO { + + @Schema(description = "旧密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "旧密码不能为空") + private String oldPassword; + + @Schema(description = "新密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "新密码不能为空") + private String newPassword; + + @Schema(description = "确认密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; +} +``` + +--- + +### Task 2: 后端 - AuthService 新增 changePassword 接口声明 + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/AuthService.java` + +在接口末尾添加: +```java +/** + * 修改密码 + * + * @param reqVO 修改密码请求 + * @return 成功返回 null + */ +void changePassword(ChangePasswordReqVO reqVO); +``` + +引入 import: +```java +import com.css.txw.sso.pojo.vo.ChangePasswordReqVO; +``` + +--- + +### Task 3: 后端 - AuthServiceImpl 实现 changePassword + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/impl/AuthServiceImpl.java` + +在类末尾添加实现方法: + +```java +@Override +public void changePassword(ChangePasswordReqVO reqVO) { + // 1. 校验新密码与确认密码一致性 + if (!reqVO.getNewPassword().equals(reqVO.getConfirmPassword())) { + throw exception(AUTH_PASSWORD_CONFIRM_MISMATCH); + } + + // 2. 密码复杂度校验(6-20位,字母+数字) + if (!isValidPasswordComplexity(reqVO.getNewPassword())) { + throw exception(AUTH_PASSWORD_COMPLEXITY_INVALID); + } + + // 3. 获取当前登录用户 + String userId = SecurityFrameworkUtils.getLoginUserId(); + YhxxbDTO yhxx = yhxxService.getYhxx(userId); + + // 4. 校验新旧密码不能相同 + if (reqVO.getOldPassword().equals(reqVO.getNewPassword())) { + throw exception(AUTH_PASSWORD_SAME_AS_OLD); + } + + // 5. 旧密码正确性校验 + authenticate(yhxx.getDlzh(), reqVO.getOldPassword()); + + // 6. 更新密码 + yhxxService.updatePassword(userId, reqVO.getNewPassword()); +} + +private boolean isValidPasswordComplexity(String password) { + if (password == null || password.length() < 6 || password.length() > 20) { + return false; + } + boolean hasLetter = password.matches(".*[A-Za-z]+.*"); + boolean hasDigit = password.matches(".*[0-9]+.*"); + return hasLetter && hasDigit; +} +``` + +新增引入: +```java +import com.css.txw.sso.pojo.vo.ChangePasswordReqVO; +import com.css.txw.sso.util.SecurityFrameworkUtils; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_CONFIRM_MISMATCH; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_COMPLEXITY_INVALID; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_SAME_AS_OLD; +``` + +--- + +### Task 4: 后端 - ErrorCodeConstants 新增错误码 + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/constants/ErrorCodeConstants.java` + +新增三个错误码: +```java +AUTH_PASSWORD_CONFIRM_MISMATCH(400, "两次输入的新密码不一致"), +AUTH_PASSWORD_COMPLEXITY_INVALID(400, "密码长度6-20位,需包含字母和数字"), +AUTH_PASSWORD_SAME_AS_OLD(400, "新密码不能与原密码相同"), +``` + +--- + +### Task 5: 后端 - AuthController 新增路由 + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/controller/auth/AuthController.java` + +在类末尾添加: + +```java +@PostMapping("/changePassword") +@Operation(summary = "修改密码") +public CommonResult changePassword(@RequestBody @Valid ChangePasswordReqVO reqVO) { + authService.changePassword(reqVO); + return success(null); +} +``` + +新增引入: +```java +import com.css.txw.sso.pojo.vo.ChangePasswordReqVO; +``` + +--- + +### Task 6: 后端 - YhxxService 新增 updatePassword 方法 + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/YhxxService.java` + +末尾新增方法声明: +```java +void updatePassword(String yhUuid, String newPassword); +``` + +--- + +### Task 7: 后端 - YhxxServiceImpl 实现 updatePassword(Feign调用mhzc) + +**文件:** `txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/impl/YhxxServiceImpl.java` + +首先需要确认 mhzc 服务的 Feign 接口存在。如果 YhxxApi 不支持更新密码,则需要在 txw-sso-api 中新增 Feign 方法指向 mhzc 的更新密码接口。 + +步骤: +1. 在 `txw-sso-api` 的 `YhxxApi.java` 中新增 `updatePassword` Feign 方法 +2. 在 `txw-mhzc` 的 `TxwMhzcYhxxbService` 新增 `updatePassword` 方法 +3. 在 `TxwMhzcYhxxbServiceImpl` 实现该方法 +4. 在 mapper XML 中新增 update SQL +5. 在 `YhxxServiceImpl` 中调用该 Feign 接口 + +**YhxxApi.java (txw-sso-api) 新增:** +```java +@PostMapping("/mhzc/user/updatePassword") +@Operation(summary = "更新用户密码") +CommonResult updatePassword(@RequestParam("yhUuid") String yhUuid, @RequestParam("dlmm") String dlmm); +``` + +**TxwMhzcYhxxbService.java 新增:** +```java +String updatePassword(String yhUuid, String dlmm); +``` + +**TxwMhzcYhxxbServiceImpl.java 新增:** +```java +@Override +public String updatePassword(String yhUuid, String dlmm) { + TxwMhzcYhxxbDO yhxxbDO = new TxwMhzcYhxxbDO(); + yhxxbDO.setYhUuid(yhUuid); + yhxxbDO.setDlmm(dlmm); + this.updateById(yhxxbDO); + return "success"; +} +``` + +**TxwMhzcYhxxbMapper.xml 新增:** +```xml + + UPDATE txw_mhzc_yhxxb SET dlmm = #{dlmm} WHERE yh_uuid = #{yhUuid} + +``` + +**YhxxServiceImpl.java 实现:** +```java +@Resource +private YhxxApi yhxxApi; + +@Override +public void updatePassword(String yhUuid, String newPassword) { + yhxxApi.updatePassword(yhUuid, newPassword); +} +``` + +--- + +## 前端任务拆分(txw-mhzc-web) + +### Task 8: 前端 - 新建 api/sso.js + +**文件:** `txw-mhzc-web/src/pages/index/api/sso.js` + +```js +import { fetchSso } from '@/core/request'; + +export const changePassword = (params) => { + return fetchSso({ + url: '/sso/auth/changePassword', + data: JSON.stringify(params), + method: 'post', + loading: true, + }); +}; +``` + +--- + +### Task 9: 前端 - 新建修改密码页面 + +**文件:** `txw-mhzc-web/src/pages/index/views/yhzx/zhanghugl/index.vue` + +页面元素: +- 三个密码输入框(旧密码、新密码、确认密码) +- 确认按钮 +- 密码格式提示文字 + +校验逻辑: +1. 旧密码、新密码、确认密码不能为空 +2. 新密码长度6-20位,需包含字母和数字(提示:密码长度6-20位,需包含字母和数字) +3. 新密码与确认密码一致性(提示:两次输入的新密码不一致) +4. 提交后调用 changePassword API +5. 成功提示"密码修改成功",可跳转回工作台 + +样式参考现有的登录页面,使用 TDesign 组件库。 + +--- + +### Task 10: 前端 - 路由配置新增 zhanghugl + +**文件:** `txw-mhzc-web/src/pages/index/router/routes.js` + +在 `yhzx` 的 children 数组中新增: +```js +{ path: 'zhanghugl', component: zhanghugl, name: 'zhanghugl', meta: { title: '账号管理' } } +``` + +新增 zhanghugl 路由函数: +```js +function zhanghugl() { + return import('@/pages/index/views/yhzx/zhanghugl/index.vue'); +} +``` + +--- + +### Task 11: 前端 - 菜单配置新增"账号管理" + +**文件:** `txw-mhzc-web/src/pages/index/views/glxtSy/config.js` + +在 `menuList` 数组中新增一项: +```js +{ + value: 'zhanghugl', + title: '账号管理', + icon: 'password', +} +``` + +--- + +### Task 12: 前端 - 工作台新增修改密码快捷入口 + +**文件:** `txw-mhzc-web/src/pages/index/views/gzt/index.vue` + +在快捷操作区域新增按钮: +```html + + 修改密码 + +``` + +--- + +## 任务执行顺序 + +建议按以下顺序执行: + +1. Task 1 - 新建 ChangePasswordReqVO +2. Task 4 - 新增错误码 +3. Task 6 - YhxxService 新增 updatePassword +4. Task 7 - YhxxServiceImpl + Feign + MHZC 实现 +5. Task 2 - AuthService 新增 changePassword +6. Task 3 - AuthServiceImpl 实现 +7. Task 5 - AuthController 新增路由 +8. Task 8 - 前端 API 新建 +9. Task 9 - 前端页面新建 +10. Task 10 - 路由配置 +11. Task 11 - 菜单配置 +12. Task 12 - 工作台入口 diff --git a/docs/superpowers/specs/2026-04-28-修改密码功能设计.md b/docs/superpowers/specs/2026-04-28-修改密码功能设计.md new file mode 100644 index 0000000..07e42f5 --- /dev/null +++ b/docs/superpowers/specs/2026-04-28-修改密码功能设计.md @@ -0,0 +1,147 @@ +# 修改密码功能设计 + +## 1. 概述 + +为碳信网平台添加普通用户自助修改密码功能,采用前后端分离架构。 + +- **普通用户修改密码**:位于 `txw-mhzc`(用户中心),入口在个人中心左侧菜单 +- **管理员重置密码**:已存在于 `txw-yygl`,无需改动 + +--- + +## 2. 后端接口 + +### 2.1 新增接口 + +**POST `/sso/auth/changePassword`** + +请求体: +```json +{ + "oldPassword": "MD5加密字符串", + "newPassword": "MD5加密字符串", + "confirmPassword": "MD5加密字符串" +} +``` + +响应(统一 `CommonResult`): +```json +{ + "code": 1, + "data": null, + "msg": "密码修改成功" +} +``` + +### 2.2 密码复杂度规则 + +**中等级别**: +- 长度:6-20 位 +- 必须包含:字母 + 数字 + +### 2.3 校验流程 + +1. **格式校验**:新密码长度6-20位,需同时包含字母和数字 +2. **一致性校验**:newPassword === confirmPassword +3. **身份校验**:authenticate(username, oldPassword) 验证旧密码正确性 +4. **防重名校验**:newPassword !== oldPassword + +### 2.4 错误码 + +| 场景 | msg | +|------|-----| +| 密码格式不符 | 密码长度6-20位,需包含字母和数字 | +| 两次密码不一致 | 两次输入的新密码不一致 | +| 旧密码错误 | 原密码输入错误 | +| 新旧密码相同 | 新密码不能与原密码相同 | + +### 2.5 涉及文件 + +| 文件 | 改动 | +|------|------| +| `AuthService.java` | 新增 `changePassword` 接口声明 | +| `AuthServiceImpl.java` | 实现 `changePassword` 逻辑 | +| `AuthController.java` | 新增 `/auth/changePassword` 路由 | +| `AuthLoginReqVO.java` | 建议复用或新建 `ChangePasswordReqVO` | + +--- + +## 3. 前端页面(txw-mhzc-web) + +### 3.1 路由 + +| 路由路径 | 组件 | 菜单标题 | +|---------|------|---------| +| `/yhzx/zhanghugl` | `ChangePassword.vue` | 账号管理 | + +### 3.2 工作台入口 + +在 `txw-mhzc-web/src/pages/index/views/gzt/index.vue` 新增快捷操作按钮"修改密码",点击跳转 `/yhzx/zhanghugl`。 + +### 3.3 用户中心左侧菜单 + +在 `yhzx` 路由的 children 中新增: +```js +{ path: 'zhanghugl', component: zhanghugl, name: 'zhanghugl', meta: { title: '账号管理' } } +``` + +### 3.4 修改密码页面 `ChangePassword.vue` + +**页面元素**: +- 旧密码输入框(密码类型) +- 新密码输入框(密码类型) +- 确认密码输入框(密码类型) +- 确认按钮 + +**交互逻辑**: +- 输入框下方实时显示密码格式提示 +- 提交前统一校验 +- 成功后给出提示并可跳转其他页面 +- 失败回显错误信息 + +### 3.5 API 调用 + +```js +// txw-mhzc-web/src/pages/index/api/sso.js +export const changePassword = (params) => { + return fetchSso({ + url: '/sso/auth/changePassword', + data: JSON.stringify(params), + method: 'post', + loading: true, + }); +}; +``` + +### 3.6 涉及文件 + +| 文件 | 改动 | +|------|------| +| `router/routes.js` | 新增 `zhanghugl` 路由 | +| `views/gzt/index.vue` | 新增修改密码快捷入口 | +| `views/yhzx/zhanghugl/index.vue` | 新建修改密码页面 | +| `api/sso.js` | 新建,封装 changePassword API | + +--- + +## 4. yygl 管理员重置密码(已有,无需改动) + +| 文件 | 说明 | +|------|------| +| `txw-yygl-web/.../yhgl/index.vue` | "重置密码"按钮,调用 `resetPassword(yhUuid)` | +| `txw-yygl-web/.../api/htgl.js` | `resetPassword` 接口已实现 | +| `txw-mhzc/.../UserController.java` | `resetPassword` 接口已实现,重置为配置默认密码 | + +--- + +## 5. 数据库字段 + +用户表 `dlmm` 字段存储 MD5 加密后的密码。 + +--- + +## 6. 备注 + +- 旧密码传输前已在前端做 MD5 加密(与现有登录流程一致) +- 新密码传输前在前端做 MD5 加密 +- 此设计与现有 `authenticate` 的 `isPasswordMatch` 逻辑保持一致 diff --git a/txw-mhzc-web/src/pages/index/api/login.js b/txw-mhzc-web/src/pages/index/api/login.js index 80491a3..4b84c57 100644 --- a/txw-mhzc-web/src/pages/index/api/login.js +++ b/txw-mhzc-web/src/pages/index/api/login.js @@ -107,6 +107,16 @@ export function mhLogout() { }); } +// 修改密码(用户自助) +export function changePassword(params) { + return fetchSso({ + headers, + url: `${basurl}/sso/auth/changePassword`, + data: JSON.stringify(params), + method: 'post', + }); +} + // 获取重定向地址 export function getRedirectUri() { return fetchSso({ diff --git a/txw-mhzc-web/src/pages/index/router/routes.js b/txw-mhzc-web/src/pages/index/router/routes.js index f39adf3..144c120 100644 --- a/txw-mhzc-web/src/pages/index/router/routes.js +++ b/txw-mhzc-web/src/pages/index/router/routes.js @@ -101,6 +101,11 @@ function search() { return import(/* webpackChunkName: "search" */ '@/pages/index/views/search/index.vue'); } +// 账号管理 +function zhanghugl() { + return import(/* webpackChunkName: "zhanghugl" */ '@/pages/index/views/yhzx/zhanghugl/index.vue'); +} + @@ -177,6 +182,7 @@ export default [ { path: 'tfwxq', component: tfwxq, name: 'tfwxq', meta: { title: '碳服务需求' } }, { path: 'ggwhgl', component: newsCenter, name: 'ggwhgl', meta: { title: '消息中心' } }, { path: 'lsjy', component: lsjy, name: 'lsjy', meta: { title: '绿色交易' } }, + { path: 'zhanghugl', component: zhanghugl, name: 'zhanghugl', meta: { title: '账号管理' } }, ] }, { diff --git a/txw-mhzc-web/src/pages/index/views/glxtSy/config.js b/txw-mhzc-web/src/pages/index/views/glxtSy/config.js index 275b298..0291f63 100644 --- a/txw-mhzc-web/src/pages/index/views/glxtSy/config.js +++ b/txw-mhzc-web/src/pages/index/views/glxtSy/config.js @@ -24,4 +24,9 @@ export const menuList = [ icon: 'circle', children: [], }, + { + value: 'zhanghugl', + title: '账号管理', + icon: 'password', + }, ]; diff --git a/txw-mhzc-web/src/pages/index/views/gzt/components/AccountShortcuts.vue b/txw-mhzc-web/src/pages/index/views/gzt/components/AccountShortcuts.vue index 4afd1ed..5819a37 100644 --- a/txw-mhzc-web/src/pages/index/views/gzt/components/AccountShortcuts.vue +++ b/txw-mhzc-web/src/pages/index/views/gzt/components/AccountShortcuts.vue @@ -45,7 +45,7 @@ export default { { label: '消息中心', icon: 'mail', to: '/yhzx/ggwhgl', bgColor: '#FCE4EC', color: '#E91E63' }, { label: '我的认证', icon: 'user', to: '/yhzx/qyrenzheng', bgColor: '#E3F2FD', color: '#2196F3' }, { label: '账号编辑', icon: 'edit', to: '/yhzx/qyrenzheng', bgColor: '#FFF8E1', color: '#FF9800' }, - { label: '修改密码', icon: 'lock-on', to: '/yhzx/qyrenzheng', bgColor: '#E8F5E9', color: '#4CAF50' }, + { label: '修改密码', icon: 'lock-on', to: '/yhzx/zhanghugl', bgColor: '#E8F5E9', color: '#4CAF50' }, ], }; }, diff --git a/txw-mhzc-web/src/pages/index/views/yhzx/zhanghugl/index.vue b/txw-mhzc-web/src/pages/index/views/yhzx/zhanghugl/index.vue new file mode 100644 index 0000000..1d9834c --- /dev/null +++ b/txw-mhzc-web/src/pages/index/views/yhzx/zhanghugl/index.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/api/IMhzcApi.java b/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/api/IMhzcApi.java index 44bc517..e0b2447 100644 --- a/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/api/IMhzcApi.java +++ b/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/api/IMhzcApi.java @@ -43,25 +43,33 @@ public interface IMhzcApi { @PostMapping(PREFIX+"/getAllUserId") @Operation(summary = "用户列表") CommonResult> getAllUserId(); - + @PostMapping(PREFIX+"/initSessionByDid") - @Operation(summary = "初始化用户信息") - CommonResult initSessionByDid(@RequestBody YhxxReqDTO reqDTO); - + @Operation(summary = "初始化用户信息") + CommonResult initSessionByDid(@RequestBody YhxxReqDTO reqDTO); + @PostMapping(PREFIX+"/initSessionBySfzjhm") - @Operation(summary = "根据身份证号初始化用户信息") - CommonResult initSessionBySfzjhm(@RequestBody YhxxReqDTO reqDTO); - + @Operation(summary = "根据身份证号初始化用户信息") + CommonResult initSessionBySfzjhm(@RequestBody YhxxReqDTO reqDTO); + @PostMapping(PREFIX+"/saveYhxxByDid") - @Operation(summary = "保存did用户信息") - CommonResult saveYhxxByDid(@RequestBody YhxxbDTO yhxx); - + @Operation(summary = "保存did用户信息") + CommonResult saveYhxxByDid(@RequestBody YhxxbDTO yhxx); + @PostMapping(QYRZ_PREFIX+"/intQyxxByDid") - @Operation(summary = "did企业认证信息") - CommonResult intQyxxByDid(@RequestBody YhxxbDTO qyxx); + @Operation(summary = "did企业认证信息") + CommonResult intQyxxByDid(@RequestBody YhxxbDTO qyxx); @PostMapping(PREFIX+"/updateDid") - @Operation(summary = "更新用户did信息") - CommonResult updateDid(@RequestBody YhxxbDTO yhxx); + @Operation(summary = "更新用户did信息") + CommonResult updateDid(@RequestBody YhxxbDTO yhxx); + + @PostMapping(PREFIX+"/updatePassword") + @Operation(summary = "更新用户密码") + CommonResult updatePassword(@RequestBody YhxxReqDTO reqDTO); + + @PostMapping(PREFIX+"/resetPassword") + @Operation(summary = "重置用户密码") + CommonResult resetPassword(@RequestBody YhxxReqDTO reqDTO); } diff --git a/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/pojo/YhxxReqDTO.java b/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/pojo/YhxxReqDTO.java index 0c23cfe..fdcd490 100644 --- a/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/pojo/YhxxReqDTO.java +++ b/txw-mhzc/txw-mhzc-service-api/src/main/java/com/css/txw/mhzc/pojo/YhxxReqDTO.java @@ -18,4 +18,6 @@ public class YhxxReqDTO implements Serializable { private String scxzmx; private String did; private String sfzjhm; + private String dlmm; + private String oldPassword; } \ No newline at end of file diff --git a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/controller/UserController.java b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/controller/UserController.java index 0d12465..0bd6a64 100644 --- a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/controller/UserController.java +++ b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/controller/UserController.java @@ -113,10 +113,16 @@ public class UserController { return CommonResult.success(yhxxbService.getAllUserId()); } - @GetMapping("/resetPassword") - @Operation(summary = "用户列表") - CommonResult resetPassword(@RequestParam("yhUuid") String yhuuid){ - return CommonResult.success(yhxxbService.resetPassword(yhuuid)); + @PostMapping("/resetPassword") + @Operation(summary = "重置密码") + CommonResult resetPassword(@RequestBody YhxxReqDTO reqDTO){ + return CommonResult.success(yhxxbService.resetPassword(reqDTO.getYhuuid(), reqDTO.getDlmm())); + } + + @PostMapping("/updatePassword") + @Operation(summary = "更新密码") + CommonResult updatePassword(@RequestBody YhxxReqDTO reqDTO){ + return CommonResult.success(yhxxbService.updatePassword(reqDTO.getYhuuid(), reqDTO.getDlmm(), reqDTO.getOldPassword())); } } diff --git a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/TxwMhzcYhxxbService.java b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/TxwMhzcYhxxbService.java index 0ed9c0e..6e24477 100644 --- a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/TxwMhzcYhxxbService.java +++ b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/TxwMhzcYhxxbService.java @@ -27,8 +27,6 @@ public interface TxwMhzcYhxxbService extends IService { Page getAllUser(UserReqVO reqVO); - String resetPassword(String yhuuid); - List getAllUserId(); Integer lockUser(UserLockVO infoVO); @@ -41,5 +39,9 @@ public interface TxwMhzcYhxxbService extends IService { YhxxbDTO saveYhxxByDid(YhxxbDTO yhxx); - YhxxbDTO updateDid(YhxxbDTO yhxx); + YhxxbDTO updateDid(YhxxbDTO yhxx); + + String updatePassword(String yhUuid, String dlmm, String oldPassword); + + String resetPassword(String yhUuid, String dlmm); } diff --git a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/impl/TxwMhzcYhxxbServiceImpl.java b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/impl/TxwMhzcYhxxbServiceImpl.java index 0e0b574..ef93d27 100644 --- a/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/impl/TxwMhzcYhxxbServiceImpl.java +++ b/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/service/impl/TxwMhzcYhxxbServiceImpl.java @@ -243,14 +243,28 @@ public class TxwMhzcYhxxbServiceImpl extends ServiceImpl getAllUserId() { List allUserId = yhxxbMapper.getAllUserId(); diff --git a/txw-sso/txw-sso-service-api/src/main/java/com/css/txw/sso/api/yhxx/YhxxApi.java b/txw-sso/txw-sso-service-api/src/main/java/com/css/txw/sso/api/yhxx/YhxxApi.java deleted file mode 100644 index fa6bd9c..0000000 --- a/txw-sso/txw-sso-service-api/src/main/java/com/css/txw/sso/api/yhxx/YhxxApi.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.css.txw.sso.api.yhxx; - -import com.css.ggzc.framework.common.pojo.CommonResult; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@FeignClient(name = "sso-service") -@Tag(name = "用户信息接口") -public interface YhxxApi { - - @PostMapping("/sso/yhxx/getYhxx") - @Operation(summary = "获取用户信息") - CommonResult getYhxx(@RequestParam("djxh") String djxh); - -} diff --git a/txw-sso/txw-sso-service-api/target/classes/com/css/txw/sso/api/yhxx/YhxxApi.class b/txw-sso/txw-sso-service-api/target/classes/com/css/txw/sso/api/yhxx/YhxxApi.class deleted file mode 100644 index 867a4a4606da76b97a77157e96caac3e1f7cab8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 820 zcmb_aJ#Q015Ssh4wt_cSFD*6_mtjJLT0cv0%gaploqvM-J98Fu*LAp3+D%188kPi% zw~V$j6kZ9~_#c?}e&=ge9{=wd>uP@&XU+jPR^m_RGy?|?{sjthZYf%2w40r!|hNgO2C<-MEH?MTM zgKYs5Em!zNt(uevs>K~I=jKLSv4ER@#7ZYka&uEzIDYLtz8tym^0V3L)& zPRjR8!rsDPL changePassword(HttpServletRequest request, @RequestBody @Valid ChangePasswordReqVO reqVO) { + String token = SecurityFrameworkUtils.obtainAuthorization(SsoConstants.COOKIE_TOKEN_KEY, request); + authService.changePassword(token, reqVO); + return success(null); + } + + @PostMapping("/resetPassword") + @Operation(summary = "重置密码") + public CommonResult resetPassword(@RequestParam("yhUuid") String yhUuid) { + authService.resetPassword(yhUuid); + return success(null); + } } diff --git a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/pojo/vo/ChangePasswordReqVO.java b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/pojo/vo/ChangePasswordReqVO.java new file mode 100644 index 0000000..cc9f9f5 --- /dev/null +++ b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/pojo/vo/ChangePasswordReqVO.java @@ -0,0 +1,29 @@ +package com.css.txw.sso.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Schema(description = "修改密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChangePasswordReqVO { + + @Schema(description = "旧密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "旧密码不能为空") + private String oldPassword; + + @Schema(description = "新密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "新密码不能为空") + private String newPassword; + + @Schema(description = "确认密码(MD5加密)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; +} \ No newline at end of file diff --git a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/AuthService.java b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/AuthService.java index 8826fc4..0ac0dad 100644 --- a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/AuthService.java +++ b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/AuthService.java @@ -3,6 +3,7 @@ package com.css.txw.sso.service.auth; import com.css.txw.mhzc.pojo.YhxxbDTO; import com.css.txw.sso.pojo.vo.AuthLoginReqVO; import com.css.txw.sso.pojo.vo.AuthLoginRespVO; +import com.css.txw.sso.pojo.vo.ChangePasswordReqVO; import com.css.txw.sso.pojo.vo.DidBindPhoneReqVO; import com.css.txw.sso.pojo.vo.SMSLoginReqVO; import com.css.txw.sso.pojo.vo.SendMsgReqVO; @@ -52,4 +53,19 @@ public interface AuthService { AuthLoginRespVO loginBySMS(SMSLoginReqVO reqVO); AuthLoginRespVO didBindPhone(@Valid DidBindPhoneReqVO reqVO); + + /** + * 修改密码 + * + * @param token 当前用户的访问令牌 + * @param reqVO 修改密码请求 + */ + void changePassword(String token, ChangePasswordReqVO reqVO); + + /** + * 重置密码(管理员操作,重置为默认密码) + * + * @param yhUuid 用户UUID + */ + void resetPassword(String yhUuid); } diff --git a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/impl/AuthServiceImpl.java b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/impl/AuthServiceImpl.java index 69b8d5b..1ba09c5 100644 --- a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/impl/AuthServiceImpl.java +++ b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/auth/impl/AuthServiceImpl.java @@ -6,6 +6,9 @@ import static com.css.ggzc.framework.common.exception.util.ServiceExceptionUtil. import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS; import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_LOGIN_CAPTCHA_CODE_ERROR; import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_LOGIN_PASSWORD_ERROR_LOCK; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_CONFIRM_MISMATCH; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_COMPLEXITY_INVALID; +import static com.css.txw.sso.constants.ErrorCodeConstants.AUTH_PASSWORD_SAME_AS_OLD; import static com.css.txw.sso.constants.ErrorCodeConstants.OAUTH2_LOGIN_SJHM_NOT_EXISTS; import static com.css.txw.sso.constants.ErrorCodeConstants.OAUTH2_LOGIN_SMS_NOT_EXISTS; import static com.css.txw.sso.constants.ErrorCodeConstants.OAUTH2_SJHM_LOCK; @@ -37,6 +40,7 @@ import com.css.ggzc.framework.common.util.json.JsonUtils; import com.css.txw.common.pojo.dto.sms.SMSResDTO; import com.css.txw.common.service.ISMService; import com.css.txw.mhzc.pojo.YhxxbDTO; +import com.css.txw.sso.pojo.dto.session.SessionInfo; import com.css.txw.sso.configuration.SMSClient; import com.css.txw.sso.controller.thirdparty.DidController; import com.css.txw.sso.convert.AuthConvert; @@ -44,6 +48,7 @@ import com.css.txw.sso.pojo.domain.oauth2.OAuth2AccessTokenDO; import com.css.txw.sso.pojo.domain.oauth2.OAuth2ClientDO; import com.css.txw.sso.pojo.vo.AuthLoginReqVO; import com.css.txw.sso.pojo.vo.AuthLoginRespVO; +import com.css.txw.sso.pojo.vo.ChangePasswordReqVO; import com.css.txw.sso.pojo.vo.DidBindPhoneReqVO; import com.css.txw.sso.pojo.vo.SMSLoginReqVO; import com.css.txw.sso.pojo.vo.SendMsgReqVO; @@ -324,4 +329,69 @@ public class AuthServiceImpl implements AuthService { return String.format(PHONE_LOCK, phone); } + @Override + public void changePassword(String token, ChangePasswordReqVO reqVO) { + // 1. 校验新密码与确认密码一致性 + if (!reqVO.getNewPassword().equals(reqVO.getConfirmPassword())) { + throw exception(AUTH_PASSWORD_CONFIRM_MISMATCH); + } + + // 2. 密码复杂度校验(6-20位,字母+数字) + if (!isValidPasswordComplexity(reqVO.getNewPassword())) { + throw exception(AUTH_PASSWORD_COMPLEXITY_INVALID); + } + + // 3. 通过token解析获取当前登录用户 + log.info("changePassword token: {}", token); + SessionInfo sessionInfo = oauth2TokenService.checkAccessToken(token); + log.info("changePassword sessionInfo: {}", sessionInfo); + if (sessionInfo == null) { + log.error("changePassword token解析失败, token: {}", token); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + // 优先使用currentYhuuid,如果为空则使用tokenInfo中的yhUuid + String yhUuid = sessionInfo.getCurrentYhuuid(); + if (GyUtils.isNull(yhUuid)) { + yhUuid = sessionInfo.getTokenInfo().getYhUuid(); + } + if (GyUtils.isNull(yhUuid)) { + yhUuid = sessionInfo.getYhxx().getYhuuid(); + } + log.info("changePassword yhUuid from token: {}", yhUuid); + YhxxbDTO yhxx = yhxxService.getYhxx(yhUuid); + log.info("changePassword yhxx: {}", yhxx); + if (yhxx == null) { + log.error("changePassword 用户不存在, yhUuid: {}", yhUuid); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + + // 4. 校验新旧密码不能相同 + if (reqVO.getOldPassword().equals(reqVO.getNewPassword())) { + throw exception(AUTH_PASSWORD_SAME_AS_OLD); + } + + // 5. 旧密码正确性校验 + authenticate(yhxx.getDlzh(), reqVO.getOldPassword()); + + // 6. 更新密码(SSO已验证旧密码,mhzc再次验证后更新) + yhxxService.updatePassword(yhxx.getYhUuid(), reqVO.getNewPassword(), reqVO.getOldPassword()); + } + + @Override + public void resetPassword(String yhUuid) { + // 获取默认密码(从配置中读取) + String defaultPassword = CacheUtils.dm2mc("cs_ggzc_xtcs", "dlmm"); + // 调用 mhzc 更新密码 + yhxxService.resetPassword(yhUuid, defaultPassword); + } + + private boolean isValidPasswordComplexity(String password) { + if (password == null || password.length() < 6 || password.length() > 20) { + return false; + } + boolean hasLetter = password.matches(".*[A-Za-z]+.*"); + boolean hasDigit = password.matches(".*[0-9]+.*"); + return hasLetter && hasDigit; + } + } diff --git a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/YhxxService.java b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/YhxxService.java index bccf744..e16f242 100644 --- a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/YhxxService.java +++ b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/YhxxService.java @@ -39,6 +39,10 @@ public interface YhxxService { YhxxbDTO intQyxxByDid(YhxxbDTO qyxx); - YhxxbDTO updateDid(YhxxbDTO yhxx); + YhxxbDTO updateDid(YhxxbDTO yhxx); + + void updatePassword(String yhUuid, String newPassword, String oldPassword); + + void resetPassword(String yhUuid, String newPassword); } diff --git a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/impl/YhxxServiceImpl.java b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/impl/YhxxServiceImpl.java index 51f49eb..44bbf7e 100644 --- a/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/impl/YhxxServiceImpl.java +++ b/txw-sso/txw-sso-service-biz/src/main/java/com/css/txw/sso/service/yhxx/impl/YhxxServiceImpl.java @@ -243,5 +243,22 @@ public class YhxxServiceImpl implements YhxxService { return data; } + @Override + public void updatePassword(String yhUuid, String newPassword, String oldPassword) { + YhxxReqDTO reqDTO = new YhxxReqDTO(); + reqDTO.setYhuuid(yhUuid); + reqDTO.setDlmm(newPassword); + reqDTO.setOldPassword(oldPassword); + mhzcApi.updatePassword(reqDTO); + } + + @Override + public void resetPassword(String yhUuid, String newPassword) { + YhxxReqDTO reqDTO = new YhxxReqDTO(); + reqDTO.setYhuuid(yhUuid); + reqDTO.setDlmm(newPassword); + mhzcApi.resetPassword(reqDTO); + } + } diff --git a/txw-yygl-web/src/pages/index/api/htgl.js b/txw-yygl-web/src/pages/index/api/htgl.js index f90a575..cae3772 100644 --- a/txw-yygl-web/src/pages/index/api/htgl.js +++ b/txw-yygl-web/src/pages/index/api/htgl.js @@ -67,8 +67,8 @@ export const getAllUser = (params) => { // 重置账号密码 export const resetPassword = (params) => { return fetchSso({ - url: `${basurl}/mhzc/user/resetPassword?yhUuid=${params}`, - method: 'get', + url: `${basurl}/sso/auth/resetPassword?yhUuid=${params}`, + method: 'post', loading: true, headers, });