1.规范增量 SQL 文件命名

2.新增数据总线模块(未完成)
3.新增规则模块(未完成)
4.新增组织编码与外部系统组织编码映射关系表
5.补全 e 办单点登录回调逻辑
This commit is contained in:
chenbowen
2025-10-15 08:59:57 +08:00
parent 97bd87de55
commit c0dc0823b6
246 changed files with 11118 additions and 2749 deletions

View File

@@ -0,0 +1,79 @@
package com.zt.plat.module.system.api.dept;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.util.collection.CollectionUtils;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.api.dept.dto.DeptExternalCodeRespDTO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptExternalCodeDO;
import com.zt.plat.module.system.service.dept.DeptExternalCodeService;
import com.zt.plat.module.system.service.dept.DeptService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
@RestController
@Validated
public class DeptExternalCodeApiImpl implements DeptExternalCodeApi {
@Resource
private DeptExternalCodeService deptExternalCodeService;
@Resource
private DeptService deptService;
@Override
public CommonResult<DeptExternalCodeRespDTO> getBySystemCodeAndExternalCode(String systemCode, String externalDeptCode) {
DeptExternalCodeDO entity = deptExternalCodeService.getBySystemCodeAndExternalCode(systemCode, externalDeptCode);
if (entity == null) {
return success(null);
}
return success(buildResp(entity));
}
@Override
public CommonResult<DeptExternalCodeRespDTO> getBySystemCodeAndDeptId(String systemCode, Long deptId) {
DeptExternalCodeDO entity = deptExternalCodeService.getBySystemCodeAndDeptId(systemCode, deptId);
if (entity == null) {
return success(null);
}
return success(buildResp(entity));
}
@Override
public CommonResult<List<DeptExternalCodeRespDTO>> getListByDeptId(Long deptId) {
List<DeptExternalCodeDO> list = deptExternalCodeService.getDeptExternalCodeListByDeptId(deptId);
List<DeptExternalCodeRespDTO> respList = BeanUtils.toBean(list, DeptExternalCodeRespDTO.class);
fillDeptInfo(respList);
return success(respList);
}
private DeptExternalCodeRespDTO buildResp(DeptExternalCodeDO entity) {
DeptExternalCodeRespDTO respDTO = BeanUtils.toBean(entity, DeptExternalCodeRespDTO.class);
fillDeptInfo(List.of(respDTO));
return respDTO;
}
private void fillDeptInfo(List<DeptExternalCodeRespDTO> list) {
if (list == null || list.isEmpty()) {
return;
}
Set<Long> deptIds = CollectionUtils.convertSet(list, DeptExternalCodeRespDTO::getDeptId);
if (deptIds == null || deptIds.isEmpty()) {
return;
}
Map<Long, DeptDO> deptMap = CollectionUtils.convertMap(deptService.getDeptList(deptIds), DeptDO::getId);
list.forEach(item -> {
DeptDO dept = deptMap.get(item.getDeptId());
if (dept != null) {
item.setDeptName(dept.getName());
item.setDeptCode(dept.getCode());
}
});
}
}

View File

@@ -99,6 +99,13 @@ public class AuthController {
return success(authService.refreshToken(refreshToken));
}
@PostMapping("/verify-password")
@Operation(summary = "校验当前密码是否正确")
public CommonResult<Boolean> verifyPassword(@RequestBody @Valid AuthVerifyPasswordReqVO reqVO) {
authService.verifyPassword(getLoginUserId(), reqVO.getPassword());
return success(Boolean.TRUE);
}
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {

View File

@@ -0,0 +1,21 @@
package com.zt.plat.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
@Schema(description = "管理后台 - 校验当前登录密码 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuthVerifyPasswordReqVO {
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@@ -0,0 +1,116 @@
package com.zt.plat.module.system.controller.admin.dept;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodePageReqVO;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodeRespVO;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodeSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptExternalCodeDO;
import com.zt.plat.module.system.service.dept.DeptExternalCodeService;
import com.zt.plat.module.system.service.dept.DeptService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 部门外部组织编码映射")
@RestController
@RequestMapping("/system/dept-external-code")
@Validated
public class DeptExternalCodeController {
@Resource
private DeptExternalCodeService deptExternalCodeService;
@Resource
private DeptService deptService;
@PostMapping("/create")
@Operation(summary = "创建外部组织编码映射")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:create')")
public CommonResult<Long> create(@Valid @RequestBody DeptExternalCodeSaveReqVO createReqVO) {
Long id = deptExternalCodeService.createDeptExternalCode(createReqVO);
return success(id);
}
@PutMapping("/update")
@Operation(summary = "修改外部组织编码映射")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:update')")
public CommonResult<Boolean> update(@Valid @RequestBody DeptExternalCodeSaveReqVO updateReqVO) {
deptExternalCodeService.updateDeptExternalCode(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除外部组织编码映射")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
deptExternalCodeService.deleteDeptExternalCode(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获取外部组织编码映射详情")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:query')")
public CommonResult<DeptExternalCodeRespVO> get(@RequestParam("id") Long id) {
DeptExternalCodeDO entity = deptExternalCodeService.getDeptExternalCode(id);
DeptExternalCodeRespVO respVO = BeanUtils.toBean(entity, DeptExternalCodeRespVO.class);
fillDeptInfo(List.of(respVO));
return success(respVO);
}
@GetMapping("/page")
@Operation(summary = "分页查询外部组织编码映射")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:query')")
public CommonResult<PageResult<DeptExternalCodeRespVO>> page(@Valid DeptExternalCodePageReqVO reqVO) {
PageResult<DeptExternalCodeDO> pageResult = deptExternalCodeService.getDeptExternalCodePage(reqVO);
PageResult<DeptExternalCodeRespVO> result = BeanUtils.toBean(pageResult, DeptExternalCodeRespVO.class);
fillDeptInfo(result.getList());
return success(result);
}
@GetMapping("/list-by-dept")
@Operation(summary = "根据部门获取外部组织编码映射")
@Parameter(name = "deptId", description = "部门编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept-external-code:query')")
public CommonResult<List<DeptExternalCodeRespVO>> listByDept(@RequestParam("deptId") Long deptId) {
List<DeptExternalCodeDO> list = deptExternalCodeService.getDeptExternalCodeListByDeptId(deptId);
List<DeptExternalCodeRespVO> respList = BeanUtils.toBean(list, DeptExternalCodeRespVO.class);
fillDeptInfo(respList);
return success(respList);
}
private void fillDeptInfo(List<DeptExternalCodeRespVO> list) {
if (list == null || list.isEmpty()) {
return;
}
Set<Long> deptIds = list.stream()
.map(DeptExternalCodeRespVO::getDeptId)
.collect(Collectors.toCollection(HashSet::new));
if (deptIds == null || deptIds.isEmpty()) {
return;
}
Map<Long, DeptDO> deptMap = deptService.getDeptList(deptIds).stream()
.collect(Collectors.toMap(DeptDO::getId, dept -> dept, (left, right) -> left));
list.forEach(item -> {
DeptDO dept = deptMap.get(item.getDeptId());
if (dept != null) {
item.setDeptName(dept.getName());
item.setDeptCode(dept.getCode());
}
});
}
}

View File

@@ -0,0 +1,41 @@
package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode;
import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 部门外部组织编码映射基础信息")
@Data
public class DeptExternalCodeBaseVO {
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "部门不能为空")
private Long deptId;
@Schema(description = "外部系统标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "ERP")
@NotBlank(message = "外部系统标识不能为空")
@Size(max = 64, message = "外部系统标识长度不能超过 64 个字符")
private String systemCode;
@Schema(description = "外部组织编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "100200")
@NotBlank(message = "外部组织编码不能为空")
@Size(max = 128, message = "外部组织编码长度不能超过 128 个字符")
private String externalDeptCode;
@Schema(description = "外部组织名称", example = "总部-华东区")
@Size(max = 255, message = "外部组织名称长度不能超过 255 个字符")
private String externalDeptName;
@Schema(description = "状态", example = "0", requiredMode = Schema.RequiredMode.REQUIRED)
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
@Schema(description = "备注", example = "用于 ERP 同步")
@Size(max = 512, message = "备注长度不能超过 512 个字符")
private String remark;
}

View File

@@ -0,0 +1,25 @@
package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode;
import com.zt.plat.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 部门外部组织编码映射分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptExternalCodePageReqVO extends PageParam {
@Schema(description = "部门编号", example = "1024")
private Long deptId;
@Schema(description = "外部系统标识", example = "ERP")
private String systemCode;
@Schema(description = "外部组织编码", example = "100200")
private String externalDeptCode;
@Schema(description = "状态", example = "0")
private Integer status;
}

View File

@@ -0,0 +1,29 @@
package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 部门外部组织编码映射 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptExternalCodeRespVO extends DeptExternalCodeBaseVO {
@Schema(description = "映射编号", example = "1024")
private Long id;
@Schema(description = "所属部门名称", example = "技术部")
private String deptName;
@Schema(description = "所属部门编码", example = "DEPT_001")
private String deptCode;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "最后更新时间")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,15 @@
package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 部门外部组织编码映射创建/修改 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptExternalCodeSaveReqVO extends DeptExternalCodeBaseVO {
@Schema(description = "映射编号", example = "1024")
private Long id;
}

View File

@@ -0,0 +1,61 @@
package com.zt.plat.module.system.dal.dataobject.dept;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 部门外部组织编码映射 DO
*
* 维护本系统部门与外部系统组织编码的映射关系
*/
@TableName("system_dept_external_code")
@KeySequence("system_dept_external_code_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptExternalCodeDO extends TenantBaseDO {
/**
* 主键编号
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 本系统部门 ID
*/
private Long deptId;
/**
* 外部系统标识
*/
private String systemCode;
/**
* 外部系统组织编码
*/
private String externalDeptCode;
/**
* 外部系统组织名称
*/
private String externalDeptName;
/**
* 映射状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,44 @@
package com.zt.plat.module.system.dal.mysql.dept;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodePageReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptExternalCodeDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeptExternalCodeMapper extends BaseMapperX<DeptExternalCodeDO> {
default PageResult<DeptExternalCodeDO> selectPage(DeptExternalCodePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DeptExternalCodeDO>()
.eqIfPresent(DeptExternalCodeDO::getDeptId, reqVO.getDeptId())
.eqIfPresent(DeptExternalCodeDO::getSystemCode, reqVO.getSystemCode())
.likeIfPresent(DeptExternalCodeDO::getExternalDeptCode, reqVO.getExternalDeptCode())
.eqIfPresent(DeptExternalCodeDO::getStatus, reqVO.getStatus())
.orderByDesc(DeptExternalCodeDO::getId));
}
default DeptExternalCodeDO selectBySystemCodeAndDeptId(String systemCode, Long deptId) {
return selectOne(new LambdaQueryWrapperX<DeptExternalCodeDO>()
.eq(DeptExternalCodeDO::getSystemCode, systemCode)
.eq(DeptExternalCodeDO::getDeptId, deptId));
}
default DeptExternalCodeDO selectBySystemCodeAndExternalCode(String systemCode, String externalDeptCode) {
return selectOne(new LambdaQueryWrapperX<DeptExternalCodeDO>()
.eq(DeptExternalCodeDO::getSystemCode, systemCode)
.eq(DeptExternalCodeDO::getExternalDeptCode, externalDeptCode));
}
default List<DeptExternalCodeDO> selectListByDeptId(Long deptId) {
return selectList(DeptExternalCodeDO::getDeptId, deptId);
}
default List<DeptExternalCodeDO> selectListBySystemCode(String systemCode) {
return selectList(DeptExternalCodeDO::getSystemCode, systemCode);
}
}

View File

@@ -19,10 +19,28 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO
return selectOne(OAuth2AccessTokenDO::getAccessToken, accessToken);
}
default OAuth2AccessTokenDO selectByAccessTokenAndClientId(String accessToken, String clientId) {
return selectOne(new LambdaQueryWrapperX<OAuth2AccessTokenDO>()
.eq(OAuth2AccessTokenDO::getAccessToken, accessToken)
.eq(OAuth2AccessTokenDO::getClientId, clientId));
}
default OAuth2AccessTokenDO selectByUserIdAndClientId(Long userId, String clientId) {
return selectOne(new LambdaQueryWrapperX<OAuth2AccessTokenDO>()
.eq(OAuth2AccessTokenDO::getUserId, userId)
.eq(OAuth2AccessTokenDO::getClientId, clientId));
}
default List<OAuth2AccessTokenDO> selectListByRefreshToken(String refreshToken) {
return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken);
}
default int deleteByUserIdAndClientId(Long userId, String clientId) {
return delete(new LambdaQueryWrapperX<OAuth2AccessTokenDO>()
.eq(OAuth2AccessTokenDO::getUserId, userId)
.eq(OAuth2AccessTokenDO::getClientId, clientId));
}
default PageResult<OAuth2AccessTokenDO> selectPage(OAuth2AccessTokenPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<OAuth2AccessTokenDO>()
.eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId())

View File

@@ -78,6 +78,14 @@ public interface AdminAuthService {
*/
AuthLoginRespVO refreshToken(String refreshToken);
/**
* 校验当前登录用户的密码是否正确
*
* @param userId 用户编号
* @param password 密码
*/
void verifyPassword(Long userId, String password);
/**
* 用户注册
*

View File

@@ -277,6 +277,20 @@ public class AdminAuthServiceImpl implements AdminAuthService {
return AuthConvert.INSTANCE.convert(accessTokenDO);
}
@Override
public void verifyPassword(Long userId, String password) {
if (userId == null) {
throw exception(USER_NOT_EXISTS);
}
AdminUserDO user = userService.getUser(userId);
if (user == null) {
throw exception(USER_NOT_EXISTS);
}
if (!userService.isPasswordMatch(password, user.getPassword())) {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
}
@Override
public void logout(String token, Integer logType) {
// 删除访问令牌

View File

@@ -0,0 +1,62 @@
package com.zt.plat.module.system.service.dept;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodePageReqVO;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodeSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptExternalCodeDO;
import java.util.List;
/**
* 部门外部组织编码映射 Service 接口
*/
public interface DeptExternalCodeService {
/**
* 创建映射关系
*
* @param createReqVO 创建请求
* @return 新增记录编号
*/
Long createDeptExternalCode(DeptExternalCodeSaveReqVO createReqVO);
/**
* 更新映射关系
*
* @param updateReqVO 更新请求
*/
void updateDeptExternalCode(DeptExternalCodeSaveReqVO updateReqVO);
/**
* 删除映射关系
*
* @param id 记录编号
*/
void deleteDeptExternalCode(Long id);
/**
* 获取映射详情
*/
DeptExternalCodeDO getDeptExternalCode(Long id);
/**
* 分页查询映射
*/
PageResult<DeptExternalCodeDO> getDeptExternalCodePage(DeptExternalCodePageReqVO reqVO);
/**
* 根据部门查询全部映射
*/
List<DeptExternalCodeDO> getDeptExternalCodeListByDeptId(Long deptId);
/**
* 根据外部系统与外部组织编码查询映射
*/
DeptExternalCodeDO getBySystemCodeAndExternalCode(String systemCode, String externalDeptCode);
/**
* 根据外部系统与部门编号查询映射
*/
DeptExternalCodeDO getBySystemCodeAndDeptId(String systemCode, Long deptId);
}

View File

@@ -0,0 +1,151 @@
package com.zt.plat.module.system.service.dept;
import cn.hutool.core.util.StrUtil;
import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodePageReqVO;
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.DeptExternalCodeSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptExternalCodeDO;
import com.zt.plat.module.system.dal.mysql.dept.DeptExternalCodeMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
/**
* 部门外部组织编码映射 Service 实现类
*/
@Service
@Validated
public class DeptExternalCodeServiceImpl implements DeptExternalCodeService {
@Resource
private DeptExternalCodeMapper deptExternalCodeMapper;
@Resource
private DeptService deptService;
@Override
public Long createDeptExternalCode(DeptExternalCodeSaveReqVO createReqVO) {
normalizeRequest(createReqVO);
validateForCreateOrUpdate(null, createReqVO.getDeptId(), createReqVO.getSystemCode(),
createReqVO.getExternalDeptCode());
DeptExternalCodeDO entity = BeanUtils.toBean(createReqVO, DeptExternalCodeDO.class);
if (entity.getStatus() == null) {
entity.setStatus(CommonStatusEnum.ENABLE.getStatus());
}
deptExternalCodeMapper.insert(entity);
return entity.getId();
}
@Override
public void updateDeptExternalCode(DeptExternalCodeSaveReqVO updateReqVO) {
normalizeRequest(updateReqVO);
DeptExternalCodeDO exists = validateExists(updateReqVO.getId());
validateForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getDeptId(), updateReqVO.getSystemCode(),
updateReqVO.getExternalDeptCode());
DeptExternalCodeDO updateObj = BeanUtils.toBean(updateReqVO, DeptExternalCodeDO.class);
// 保持原有的状态默认值逻辑
if (updateObj.getStatus() == null) {
updateObj.setStatus(exists.getStatus() == null ? CommonStatusEnum.ENABLE.getStatus() : exists.getStatus());
}
deptExternalCodeMapper.updateById(updateObj);
}
@Override
public void deleteDeptExternalCode(Long id) {
validateExists(id);
deptExternalCodeMapper.deleteById(id);
}
@Override
public DeptExternalCodeDO getDeptExternalCode(Long id) {
return deptExternalCodeMapper.selectById(id);
}
@Override
public PageResult<DeptExternalCodeDO> getDeptExternalCodePage(DeptExternalCodePageReqVO reqVO) {
return deptExternalCodeMapper.selectPage(reqVO);
}
@Override
public List<DeptExternalCodeDO> getDeptExternalCodeListByDeptId(Long deptId) {
return deptExternalCodeMapper.selectListByDeptId(deptId);
}
@Override
public DeptExternalCodeDO getBySystemCodeAndExternalCode(String systemCode, String externalDeptCode) {
if (StrUtil.hasEmpty(systemCode, externalDeptCode)) {
return null;
}
return deptExternalCodeMapper.selectBySystemCodeAndExternalCode(systemCode.trim(), externalDeptCode.trim());
}
@Override
public DeptExternalCodeDO getBySystemCodeAndDeptId(String systemCode, Long deptId) {
if (StrUtil.isBlank(systemCode) || deptId == null) {
return null;
}
return deptExternalCodeMapper.selectBySystemCodeAndDeptId(systemCode.trim(), deptId);
}
private DeptExternalCodeDO validateExists(Long id) {
if (id == null) {
throw exception(DEPT_EXTERNAL_RELATION_NOT_EXISTS);
}
DeptExternalCodeDO entity = deptExternalCodeMapper.selectById(id);
if (entity == null) {
throw exception(DEPT_EXTERNAL_RELATION_NOT_EXISTS);
}
return entity;
}
private void validateForCreateOrUpdate(Long id, Long deptId, String systemCode, String externalDeptCode) {
// 校验部门存在
DeptDO dept = deptService.getDept(deptId);
if (dept == null) {
throw exception(DEPT_NOT_FOUND);
}
String normalizedSystemCode = StrUtil.blankToDefault(systemCode, null);
String normalizedExternalCode = StrUtil.blankToDefault(externalDeptCode, null);
// 校验同一系统下部门唯一
if (StrUtil.isNotBlank(normalizedSystemCode)) {
DeptExternalCodeDO sameDept = deptExternalCodeMapper
.selectBySystemCodeAndDeptId(normalizedSystemCode, deptId);
if (sameDept != null && (id == null || !sameDept.getId().equals(id))) {
throw exception(DEPT_EXTERNAL_RELATION_EXISTS, normalizedSystemCode);
}
}
// 校验同一系统下外部编码唯一
if (StrUtil.isNotBlank(normalizedSystemCode) && StrUtil.isNotBlank(normalizedExternalCode)) {
DeptExternalCodeDO sameExternal = deptExternalCodeMapper
.selectBySystemCodeAndExternalCode(normalizedSystemCode, normalizedExternalCode);
if (sameExternal != null && (id == null || !sameExternal.getId().equals(id))) {
throw exception(DEPT_EXTERNAL_CODE_DUPLICATE, normalizedSystemCode, normalizedExternalCode);
}
}
}
private void normalizeRequest(DeptExternalCodeSaveReqVO reqVO) {
if (reqVO == null) {
return;
}
if (StrUtil.isNotBlank(reqVO.getSystemCode())) {
reqVO.setSystemCode(reqVO.getSystemCode().trim());
}
if (StrUtil.isNotBlank(reqVO.getExternalDeptCode())) {
reqVO.setExternalDeptCode(reqVO.getExternalDeptCode().trim());
}
if (reqVO.getStatus() == null) {
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
}
}
}

View File

@@ -36,6 +36,8 @@ public interface EbanOAuth2Service {
private String email;
private String mobile;
private String deptName;
private String uid;
private String rawUserInfoJson;
private EbanOAuth2ServiceImpl.EbanTokenInfo tokenInfo; // 添加Token信息
// 构造函数
@@ -65,6 +67,12 @@ public interface EbanOAuth2Service {
public String getDeptName() { return deptName; }
public void setDeptName(String deptName) { this.deptName = deptName; }
public String getUid() { return uid; }
public void setUid(String uid) { this.uid = uid; }
public String getRawUserInfoJson() { return rawUserInfoJson; }
public void setRawUserInfoJson(String rawUserInfoJson) { this.rawUserInfoJson = rawUserInfoJson; }
public EbanOAuth2ServiceImpl.EbanTokenInfo getTokenInfo() { return tokenInfo; }
public void setTokenInfo(EbanOAuth2ServiceImpl.EbanTokenInfo tokenInfo) { this.tokenInfo = tokenInfo; }
}

View File

@@ -6,8 +6,9 @@ import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.module.system.controller.admin.auth.vo.AuthOAuth2CallbackReqVO;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.zt.plat.module.system.controller.admin.auth.vo.AuthOAuth2CallbackReqVO;
import com.zt.plat.module.system.convert.auth.AuthConvert;
import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
@@ -16,11 +17,11 @@ import com.zt.plat.module.system.enums.logger.LoginResultEnum;
import com.zt.plat.module.system.enums.oauth2.OAuth2ClientConstants;
import com.zt.plat.module.system.service.logger.LoginLogService;
import com.zt.plat.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@@ -36,6 +37,8 @@ import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
@Service
@Slf4j
public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
private static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
@Resource
private AdminUserService userService;
@@ -69,89 +72,87 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
log.info("处理E办OAuth2回调: code={}, state={}", reqVO.getCode(), reqVO.getState());
try {
// 1. 通过授权码获取用户信息
EbanUserInfo userInfo = getUserInfo(reqVO.getCode(), reqVO.getState());
if (userInfo == null || StrUtil.isBlank(userInfo.getUsername())) {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
if (userInfo == null) {
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
// 2. 根据用户名查找系统用户
AdminUserDO user = userService.getUserByUsername(userInfo.getUsername());
String uid = userInfo.getUid();
if (StrUtil.isBlank(uid)) {
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
Long userId = parseUid(uid);
AdminUserDO user = userService.getUser(userId);
if (user == null) {
// 用户不存在,记录登录失败日志
createLoginLog(null, userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
throw exception(USER_NOT_EXISTS);
createLoginLog(null, uid, LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
throw exception(AUTH_LOGIN_EBAN_USER_NOT_SYNC);
}
// 3. 校验用户状态
if (CommonStatusEnum.isDisable(user.getStatus())) {
createLoginLog(user.getId(), userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.USER_DISABLED);
createLoginLog(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.USER_DISABLED);
throw exception(AUTH_LOGIN_USER_DISABLED);
}
// 4. 保存E办token到现有OAuth2表中
try {
EbanTokenInfo tokenInfo = userInfo.getTokenInfo();
if (tokenInfo != null) {
// 将用户信息转换为JSON字符串
JSONObject ebanUserInfoJson = new JSONObject();
ebanUserInfoJson.put("username", userInfo.getUsername());
ebanUserInfoJson.put("realName", userInfo.getRealName());
ebanUserInfoJson.put("email", userInfo.getEmail());
ebanUserInfoJson.put("mobile", userInfo.getMobile());
ebanUserInfoJson.put("deptName", userInfo.getDeptName());
if (tokenInfo != null && StrUtil.isNotBlank(tokenInfo.getAccessToken())) {
String userInfoJson = StrUtil.blankToDefault(userInfo.getRawUserInfoJson(), buildBasicUserInfoJson(userInfo));
Long tenantId = user.getTenantId() != null ? user.getTenantId() : 0L;
ebanTokenService.createEbanToken(
user.getId(), // 使用用户ID
tokenInfo.getAccessToken(),
tokenInfo.getRefreshToken(),
tokenInfo.getExpiresIn(),
tokenInfo.getUid(),
ebanUserInfoJson.toString()
user.getId(),
tenantId,
tokenInfo.getAccessToken(),
tokenInfo.getRefreshToken(),
tokenInfo.getExpiresIn(),
uid,
userInfoJson
);
log.info("成功保存E办token到OAuth2表用户ID: {}, 用户名: {}, uid: {}",
user.getId(), userInfo.getUsername(), tokenInfo.getUid());
log.info("成功保存E办tokenuserId={}, uid={}", user.getId(), uid);
}
} catch (Exception e) {
log.error("保存E办token失败用户: " + userInfo.getUsername(), e);
// 保存token失败不影响登录流程继续执行
log.error("保存E办token失败userId={}, uid={}", user.getId(), uid, e);
}
// 5. 创建Token令牌记录登录日志
return createTokenAfterLoginSuccess(user.getId(), userInfo.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("E办OAuth2回调处理失败", e);
if (e.getMessage().contains("USER_NOT_EXISTS") || e.getMessage().contains("AUTH_LOGIN_USER_DISABLED")) {
throw e; // 重新抛出业务异常
}
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
throw exception(AUTH_OAUTH2_CALLBACK_ERROR, e.getMessage());
}
}
@Override
public EbanUserInfo getUserInfo(String code, String state) {
try {
// 1. 使用授权码换取access_token
EbanTokenInfo tokenInfo = exchangeAccessToken(code, state);
if (tokenInfo == null || StrUtil.isBlank(tokenInfo.getAccessToken())) {
log.error("获取access_token失败");
return null;
}
// 2. 使用access_token获取用户信息
EbanUserInfo userInfo = fetchUserInfo(tokenInfo.getAccessToken());
if (userInfo != null) {
// 将Token信息保存到用户信息中以便后续使用
userInfo.setTokenInfo(tokenInfo);
}
return userInfo;
} catch (Exception e) {
log.error("获取E办用户信息失败", e);
return null;
EbanTokenInfo tokenInfo = exchangeAccessToken(code, state);
EbanUserInfo userInfo = fetchUserInfo(tokenInfo.getAccessToken());
userInfo.setTokenInfo(tokenInfo);
if (StrUtil.isBlank(userInfo.getUid()) && StrUtil.isNotBlank(tokenInfo.getUid())) {
userInfo.setUid(tokenInfo.getUid());
}
return userInfo;
}
private Long parseUid(String uid) {
try {
return Long.parseLong(uid);
} catch (NumberFormatException ex) {
log.warn("E办uid无法解析: {}", uid);
throw exception(AUTH_LOGIN_EBAN_USER_NOT_SYNC);
}
}
private String buildBasicUserInfoJson(EbanUserInfo userInfo) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("uid", userInfo.getUid());
jsonObject.put("loginName", userInfo.getUsername());
jsonObject.put("realName", userInfo.getRealName());
jsonObject.put("email", userInfo.getEmail());
jsonObject.put("mobile", userInfo.getMobile());
jsonObject.put("deptName", userInfo.getDeptName());
return jsonObject.toString();
}
/**
@@ -195,121 +196,116 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
* 使用授权码换取access_token
*/
private EbanTokenInfo exchangeAccessToken(String code, String state) {
try {
// 根据e办API规范构建请求参数
Map<String, Object> params = new HashMap<>();
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
params.put("code", code);
params.put("grant_type", "authorization_code");
log.info("请求e办获取token参数: client_id={}, code={}", clientId, code);
HttpResponse response = HttpRequest.post(tokenUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("获取access_token失败HTTP状态码: {}, 响应: {}", response.getStatus(), response.body());
return null;
}
JSONObject jsonResponse = JSONUtil.parseObj(response.body());
// 检查是否有错误码
if (jsonResponse.containsKey("errcode")) {
log.error("获取access_token失败错误码: {}, 错误信息: {}",
jsonResponse.getStr("errcode"), jsonResponse.getStr("msg"));
return null;
}
String accessToken = jsonResponse.getStr("access_token");
String refreshToken = jsonResponse.getStr("refresh_token");
Integer expiresIn = jsonResponse.getInt("expires_in");
String uid = jsonResponse.getStr("uid");
String createDate = jsonResponse.getStr("createDate");
log.info("成功获取access_tokenuid: {}, expires_in: {}", uid, expiresIn);
return new EbanTokenInfo(accessToken, refreshToken, expiresIn, uid, createDate);
} catch (Exception e) {
log.error("调用e办token接口异常", e);
return null;
Map<String, Object> params = new HashMap<>();
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
params.put("code", code);
params.put("grant_type", GRANT_TYPE_AUTHORIZATION_CODE);
log.info("请求e办获取tokenclient_id={}, state={}", clientId, state);
HttpResponse response = HttpRequest.post(tokenUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("获取access_token失败HTTP状态码: {}, 响应: {}", response.getStatus(), response.body());
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
JSONObject jsonResponse = parseResponseBody(response.body(), "获取access_token");
if (jsonResponse.containsKey("errcode")) {
log.error("获取access_token失败错误码: {}, 错误信息: {}", jsonResponse.getStr("errcode"), jsonResponse.getStr("msg"));
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
String accessToken = jsonResponse.getStr("access_token");
if (StrUtil.isBlank(accessToken)) {
log.error("获取access_token失败响应缺少access_token字段: {}", jsonResponse);
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
String refreshToken = jsonResponse.getStr("refresh_token");
Integer expiresIn = jsonResponse.getInt("expires_in");
String uid = jsonResponse.getStr("uid");
String createDate = jsonResponse.getStr("createDate");
log.info("成功获取E办access_tokenuid={}, expires_in={}", uid, expiresIn);
return new EbanTokenInfo(accessToken, refreshToken, expiresIn, uid, createDate);
}
/**
* 使用access_token获取用户信息
*/
private EbanUserInfo fetchUserInfo(String accessToken) {
try {
// 根据e办API规范构建请求参数
Map<String, Object> params = new HashMap<>();
params.put("client_id", clientId);
params.put("access_token", accessToken);
log.info("请求e办获取用户信息client_id: {}", clientId);
HttpResponse response = HttpRequest.get(userInfoUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("获取用户信息失败HTTP状态码: {}, 响应: {}", response.getStatus(), response.body());
return null;
}
JSONObject userJson = JSONUtil.parseObj(response.body());
// 检查是否有错误码
if (userJson.containsKey("errcode")) {
log.error("获取用户信息失败,错误码: {}, 错误信息: {}",
userJson.getStr("errcode"), userJson.getStr("msg"));
return null;
}
// 解析用户信息根据e办系统的实际返回格式调整
EbanUserInfo userInfo = new EbanUserInfo();
// 根据API文档主要字段是loginName和spRoleList
String loginName = userJson.getStr("loginName");
if (StrUtil.isBlank(loginName)) {
log.error("用户信息中缺少loginName字段");
return null;
}
userInfo.setUsername(loginName); // 使用loginName作为用户名
// 如果有spRoleList可以取第一个作为真实姓名或其他用途
if (userJson.containsKey("spRoleList")) {
Object spRoleListObj = userJson.get("spRoleList");
if (spRoleListObj instanceof java.util.List) {
@SuppressWarnings("unchecked")
java.util.List<String> spRoleList = (java.util.List<String>) spRoleListObj;
if (!spRoleList.isEmpty()) {
userInfo.setRealName(spRoleList.get(0));
Map<String, Object> params = new HashMap<>();
params.put("client_id", clientId);
params.put("access_token", accessToken);
log.info("请求e办获取用户信息client_id={}", clientId);
HttpResponse response = HttpRequest.get(userInfoUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("获取用户信息失败HTTP状态码: {}, 响应: {}", response.getStatus(), response.body());
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
JSONObject userJson = parseResponseBody(response.body(), "获取用户信息");
if (userJson.containsKey("errcode")) {
log.error("获取用户信息失败,错误码: {}, 错误信息: {}", userJson.getStr("errcode"), userJson.getStr("msg"));
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
String loginName = userJson.getStr("loginName");
if (StrUtil.isBlank(loginName)) {
log.error("获取用户信息失败响应缺少loginName字段: {}", userJson);
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
EbanUserInfo userInfo = new EbanUserInfo();
userInfo.setUsername(loginName);
userInfo.setRealName(userJson.getStr("realName"));
userInfo.setEmail(userJson.getStr("email"));
userInfo.setMobile(userJson.getStr("mobile"));
userInfo.setDeptName(userJson.getStr("deptName"));
userInfo.setUid(userJson.getStr("uid"));
userInfo.setRawUserInfoJson(userJson.toString());
if (StrUtil.isBlank(userInfo.getRealName()) && userJson.containsKey("spRoleList")) {
Object spRoleListObj = userJson.get("spRoleList");
if (spRoleListObj instanceof java.util.List<?>) {
java.util.List<?> spRoleList = (java.util.List<?>) spRoleListObj;
if (!spRoleList.isEmpty()) {
Object first = spRoleList.get(0);
if (first != null) {
userInfo.setRealName(String.valueOf(first));
}
}
}
// 其他可能的字段根据实际e办返回的字段调整
userInfo.setEmail(userJson.getStr("email"));
userInfo.setMobile(userJson.getStr("mobile"));
userInfo.setDeptName(userJson.getStr("deptName"));
log.info("成功获取用户信息: username={}, realName={}", userInfo.getUsername(), userInfo.getRealName());
return userInfo;
} catch (Exception e) {
log.error("调用e办用户信息接口异常", e);
return null;
}
log.info("成功获取E办用户信息: uid={}, loginName={}", userInfo.getUid(), userInfo.getUsername());
return userInfo;
}
private JSONObject parseResponseBody(String body, String action) {
try {
return JSONUtil.parseObj(body);
} catch (Exception ex) {
log.error("{}失败响应内容无法解析为JSON: {}", action, body, ex);
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
}
/**
* 创建登录日志
*/

View File

@@ -1,7 +1,6 @@
package com.zt.plat.module.system.service.oauth2;
import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
/**
* E办Token管理服务接口基于现有OAuth2 Token体系
@@ -14,6 +13,7 @@ public interface EbanTokenService {
* 创建E办Token信息到现有OAuth2表中
*
* @param userId 系统用户ID
* @param tenantId 租户编号
* @param accessToken E办访问令牌
* @param refreshToken E办刷新令牌
* @param expiresIn 过期时间(秒)
@@ -21,7 +21,7 @@ public interface EbanTokenService {
* @param userInfo E办用户信息JSON格式
* @return OAuth2AccessTokenDO
*/
OAuth2AccessTokenDO createEbanToken(Long userId, String accessToken, String refreshToken,
OAuth2AccessTokenDO createEbanToken(Long userId, Long tenantId, String accessToken, String refreshToken,
Integer expiresIn, String uid, String userInfo);
/**

View File

@@ -1,22 +1,29 @@
package com.zt.plat.module.system.service.oauth2;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zt.plat.framework.common.enums.UserTypeEnum;
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.zt.plat.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import com.zt.plat.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static com.zt.plat.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_EBAN_TOKEN_INVALID;
/**
* E办Token管理服务实现类基于现有OAuth2 Token体系
*
@@ -27,7 +34,7 @@ import java.util.Map;
public class EbanTokenServiceImpl implements EbanTokenService {
@Resource
private OAuth2TokenService oauth2TokenService;
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
@Value("${eban.oauth2.auth-server.client-id:tyszhjyglxt}")
private String clientId;
@@ -42,56 +49,148 @@ public class EbanTokenServiceImpl implements EbanTokenService {
private String checkTokenUrl;
private static final String EBAN_CLIENT_ID = "eban-oauth2-client";
private static final String EBAN_SCOPES = "user:read";
private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
@Override
public OAuth2AccessTokenDO createEbanToken(Long userId, String accessToken, String refreshToken,
public OAuth2AccessTokenDO createEbanToken(Long userId, Long tenantId, String accessToken, String refreshToken,
Integer expiresIn, String uid, String userInfo) {
try {
// 使用现有的OAuth2TokenService创建token
// 由于原方法签名不匹配,我们先简单实现
OAuth2AccessTokenDO token = oauth2TokenService.createAccessToken(
userId,
UserTypeEnum.ADMIN.getValue(),
EBAN_CLIENT_ID,
java.util.Arrays.asList(EBAN_SCOPES)
);
log.info("成功创建E办Token: userId={}, uid={}", userId, uid);
return token;
} catch (Exception e) {
log.error("创建E办Token失败: userId=" + userId + ", uid=" + uid, e);
throw new RuntimeException("创建E办Token失败", e);
if (StrUtil.isBlank(accessToken)) {
throw ServiceExceptionUtil.exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
LocalDateTime expiresTime = calculateExpiresTime(expiresIn);
Map<String, String> userInfoMap = MapUtil.newHashMap(2, false);
if (StrUtil.isNotBlank(uid)) {
userInfoMap.put("uid", uid);
}
if (StrUtil.isNotBlank(userInfo)) {
userInfoMap.put("rawUserInfo", userInfo);
}
OAuth2AccessTokenDO tokenDO = oauth2AccessTokenMapper.selectByUserIdAndClientId(userId, EBAN_CLIENT_ID);
if (tokenDO == null) {
tokenDO = new OAuth2AccessTokenDO();
tokenDO.setUserId(userId);
}
tokenDO.setClientId(EBAN_CLIENT_ID);
tokenDO.setUserType(UserTypeEnum.ADMIN.getValue());
tokenDO.setTenantId(tenantId != null ? tenantId : 0L);
tokenDO.setAccessToken(accessToken);
tokenDO.setRefreshToken(refreshToken);
tokenDO.setExpiresTime(expiresTime);
tokenDO.setUserInfo(userInfoMap);
tokenDO.setScopes(Collections.singletonList("eban"));
if (tokenDO.getId() == null) {
oauth2AccessTokenMapper.insert(tokenDO);
} else {
oauth2AccessTokenMapper.updateById(tokenDO);
}
log.info("保存E办Token成功userId={}, uid={}, expiresTime={}", userId, uid, expiresTime);
return tokenDO;
}
@Override
public OAuth2AccessTokenDO getEbanTokenByUserId(Long userId) {
// 暂时返回null需要根据实际的OAuth2TokenService方法实现
return null;
return oauth2AccessTokenMapper.selectByUserIdAndClientId(userId, EBAN_CLIENT_ID);
}
@Override
public OAuth2AccessTokenDO getEbanTokenByAccessToken(String accessToken) {
return oauth2TokenService.getAccessToken(accessToken);
return oauth2AccessTokenMapper.selectByAccessTokenAndClientId(accessToken, EBAN_CLIENT_ID);
}
@Override
public boolean refreshEbanToken(Long userId) {
// 暂时简单实现
return false;
OAuth2AccessTokenDO tokenDO = getEbanTokenByUserId(userId);
if (tokenDO == null || StrUtil.isBlank(tokenDO.getRefreshToken())) {
return false;
}
Map<String, Object> params = new HashMap<>();
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
params.put("refresh_token", tokenDO.getRefreshToken());
params.put("grant_type", GRANT_TYPE_REFRESH_TOKEN);
HttpResponse response = HttpRequest.post(refreshTokenUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("刷新E办Token失败userId={},响应={}", userId, response.body());
return false;
}
JSONObject json = parseJson(response.body());
if (json.containsKey("errcode")) {
log.error("刷新E办Token失败userId={},错误码={},信息={}", userId, json.getStr("errcode"), json.getStr("msg"));
return false;
}
String newAccessToken = json.getStr("access_token");
if (StrUtil.isBlank(newAccessToken)) {
log.error("刷新E办Token失败响应缺少access_token字段: {}", json);
return false;
}
tokenDO.setAccessToken(newAccessToken);
tokenDO.setRefreshToken(StrUtil.blankToDefault(json.getStr("refresh_token"), tokenDO.getRefreshToken()));
tokenDO.setExpiresTime(calculateExpiresTime(json.getInt("expires_in")));
oauth2AccessTokenMapper.updateById(tokenDO);
log.info("刷新E办Token成功userId={}", userId);
return true;
}
@Override
public void deleteEbanToken(Long userId) {
// 暂时简单实现
log.info("删除E办Token: userId={}", userId);
if (oauth2AccessTokenMapper.deleteByUserIdAndClientId(userId, EBAN_CLIENT_ID) > 0) {
log.info("删除用户{}的E办Token", userId);
}
}
@Override
public boolean isEbanTokenValid(Long userId) {
// 暂时简单实现
return false;
OAuth2AccessTokenDO tokenDO = getEbanTokenByUserId(userId);
if (tokenDO == null || StrUtil.isBlank(tokenDO.getAccessToken())) {
return false;
}
if (tokenDO.getExpiresTime() != null && LocalDateTime.now().isAfter(tokenDO.getExpiresTime())) {
return false;
}
Map<String, Object> params = Collections.singletonMap("access_token", tokenDO.getAccessToken());
HttpResponse response = HttpRequest.get(checkTokenUrl)
.form(params)
.timeout(10000)
.execute();
if (!response.isOk()) {
log.error("校验E办Token有效性失败userId={},响应={}", userId, response.body());
return false;
}
JSONObject json = parseJson(response.body());
if (json.containsKey("errcode")) {
log.warn("校验E办Token返回错误userId={},错误码={},信息={}", userId, json.getStr("errcode"), json.getStr("msg"));
return false;
}
return StrUtil.equalsIgnoreCase(json.getStr("result"), "true");
}
private LocalDateTime calculateExpiresTime(Integer expiresIn) {
int seconds = expiresIn != null && expiresIn > 0 ? expiresIn : 3600;
return LocalDateTimeUtil.offset(LocalDateTime.now(), seconds, ChronoUnit.SECONDS);
}
private JSONObject parseJson(String body) {
try {
return JSONUtil.parseObj(body);
} catch (Exception ex) {
log.error("解析E办响应失败: {}", body, ex);
return new JSONObject();
}
}
}

View File

@@ -211,7 +211,7 @@ eban:
auth-server:
base-url: http://10.2.137.42/idp/oauth2
client-id: tyszhjyglxt
client-secret: your_client_secret_here # 需要从e办系统获取
client-secret: fa821b567e59448e9acea3937529d1b4 # 需要从e办系统获取
callback-uri: http://172.16.46.63:30080/system/oauth2/callback
# 用户信息获取配置