# 粤信签登录集成 - 后端修改记录 > 修改日期:2026-06-15 | 需求:后端一站式处理粤信签认证,前端只需传入loginToken即可完成全部登录流程 --- ## 一、修改概述 后端新增 `/zjrs/login/yxqMiniProgramLogin` 接口,接收前端传入的粤信签loginToken,内部一站式完成: 1. 调用省统一认证网关换取Access-Token 2. 用Access-Token获取用户信息(姓名、身份证号、用户类型等) 3. 根据用户信息匹配本地数据库(PERSONAL_INFO或ENTERPRISE_INFO) 4. 签发JeecgBoot业务token并返回 **核心优化:** 将原来前端需要3次网络请求的登录流程,简化为前端1次请求,后端内部完成全部逻辑。 --- ## 二、修改文件清单 ### 1. `ILoginSSOService.java` - Service接口 **文件路径:** `jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/sso/service/ILoginSSOService.java` **新增方法:** ```java /** * 粤信签小程序登录 * 前端传入粤信签返回的loginToken,后端内部调用省统一认证网关完成: * 1. 用loginToken换取Access-Token * 2. 用Access-Token获取用户信息(姓名、身份证号、用户类型等) * 3. 根据用户信息匹配本地数据库(PERSONAL_INFO或ENTERPRISE_INFO) * 4. 签发JeecgBoot业务token * * @param loginToken 粤信签小程序返回的登录token * @param request 请求对象 * @return 登录结果(包含token、loginType、personalInfoId/enterpriseInfoId等) * @throws RuntimeException 登录失败时抛出异常 */ JSONObject yxqMiniProgramLogin(String loginToken, HttpServletRequest request); ``` ### 2. `LoginSSOServiceImpl.java` - Service实现 **文件路径:** `jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/sso/service/impl/LoginSSOServiceImpl.java` **新增配置常量:** ```java /** 省统一认证平台申请ID */ private static final String PAAS_ID = "yxq_zjsrlzyhshbzggfwpt"; /** 省统一认证平台申请密钥 */ private static final String PAAS_TOKEN = "TSgNKaU3wFw1WwtdAoTE0cT57UisJs5p"; /** 网关基础地址(通过配置文件注入,默认值用于本地开发) */ @Value("${zjrs.yxq.gateway-url:https://rsj.zhanjiang.gov.cn/wx}") private String gatewayBaseUrl; ``` **新增方法:** | 方法 | 说明 | |------|------| | `yxqMiniProgramLogin()` | 入口方法,接收loginToken,内部调用网关验证+获取用户信息+匹配数据库+签发token | | `getAccessTokenFromGateway()` | 用loginToken调用省统一认证网关 `/api/auth/tyrz/miniprogram`,换取Access-Token | | `getYxqUserInfo()` | 用Access-Token调用 `/ggfw/api/portal/user/getUserInfo`,获取用户信息 | | `matchPersonalAndCreateToken()` | 个人用户匹配:优先身份证号精确匹配,其次姓名匹配 | | `matchEnterpriseAndCreateToken()` | 企业用户匹配:根据企业名称匹配 | | `sha256()` | SHA256哈希算法,用于生成粤信签网关签名 | **关键优化 - 个人用户匹配策略:** - 优先使用身份证号(`aac002`)精确匹配 `personal_info.id_number`,避免同名冲突 - 身份证号匹配不到时,再用姓名匹配 `personal_info.full_name` - 使用 `getOne(qw, false)` 避免多条记录时抛出 TooManyResultsException **新增import:** ```java import org.jeecg.common.util.RestUtil; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.UUID; ``` ### 3. `LoginSSOController.java` - Controller **文件路径:** `jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/sso/controller/LoginSSOController.java` **新增接口:** ```java @PostMapping("/yxqMiniProgramLogin") @IgnoreAuth @Operation(summary = "粤信签小程序登录", description = "前端传入粤信签loginToken,后端内部调用省统一认证网关完成认证并签发JeecgBoot业务token") public Result yxqMiniProgramLogin(@RequestBody JSONObject params, HttpServletRequest request) { try { String loginToken = params.getString("loginToken"); JSONObject result = loginSSOService.yxqMiniProgramLogin(loginToken, request); return Result.OK(result); } catch (RuntimeException e) { log.error("粤信签小程序登录失败", e); return Result.error(e.getMessage()); } } ``` ### 4. `ShiroConfig.java` - Shiro安全配置 **文件路径:** `jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java` **修改内容:** ```java filterChainDefinitionMap.put("/zjrs/login/yxqMiniProgramLogin", "anon"); // 粤信签小程序登录 ``` --- ## 三、接口说明 ### 请求 - **URL:** `POST /zjrs/login/yxqMiniProgramLogin` - **参数:** ```json { "loginToken": "粤信签小程序返回的token" } ``` ### 返回 ```json { "success": true, "result": { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "loginType": "personal", "personalInfoId": "1906017267265433601", "yxqUserInfo": { "aac003": "张三", "fwdx": "1", ... }, "loginFlag": true } } ``` --- ## 四、后端处理流程 ``` 接收 loginToken ↓ getAccessTokenFromGateway() POST {gateway-url}/api/auth/tyrz/miniprogram 参数:code, x_tif_paasid, x_tif_signature, x_tif_timestamp, x_tif_nonce 签名:sha256(时间戳 + paaSToken + 随机数 + 时间戳) 返回:Access-Token ↓ getYxqUserInfo() GET {gateway-url}/ggfw/api/portal/user/getUserInfo 请求头:Access-Token 返回:{ aac003: 姓名, aac002: 身份证号, fwdx: 用户类型 } ↓ 根据 fwdx 判断登录类型(1=个人,2=企业) ↓ 个人用户: matchPersonalAndCreateToken() 1. 优先用身份证号(aac002)匹配 personal_info.id_number 2. 匹配不到再用姓名(aac003)匹配 personal_info.full_name 3. 生成 "personal_" + id 的用户名 4. 调用 createToken() 签发JWT 企业用户: matchEnterpriseAndCreateToken() 1. 用企业名称(aac003)匹配 enterprise_info.company_name 2. 生成 "enterprise_" + id 的用户名 3. 调用 createToken() 签发JWT ↓ 返回 { token, loginType, personalInfoId/enterpriseInfoId, yxqUserInfo, loginFlag } ``` --- ## 五、注意事项 1. **网关地址配置:** 默认 `https://rsj.zhanjiang.gov.cn/wx`,如JeecgBoot部署在内网无法直接访问外网,需在 `application.yml` 中配置 `zjrs.yxq.gateway-url` 代理地址。 2. **无需新增依赖:** 使用项目已有的 `RestUtil`(基于 RestTemplate + Apache HttpClient)。 3. **个人用户匹配策略:** 优先身份证号精确匹配,解决了原来仅用姓名匹配可能导致的同名冲突问题。 4. **安全加固:** paaSToken密钥存储在后端,不再暴露在前端。 5. **不影响现有逻辑:** 原有的 `miniProgramPersonalLogin` 和 `miniProgramEnterpriseLogin` 接口保持不变。