feat: 添加小程序企业测试授权功能及相关接口

This commit is contained in:
2026-07-23 14:41:55 +08:00
parent 736dade03e
commit 487717986a
6 changed files with 392 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.config.BackDoorLoginProperties;
import com.ruoyi.web.service.BackDoorLoginService;
import com.ruoyi.web.service.BackDoorLoginService.AppLoginSession;
import com.ruoyi.web.service.BackDoorLoginService.CompanyLoginSession;
import com.ruoyi.web.service.BackDoorLoginService.LoginSession;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -150,6 +151,62 @@ public class BackDoorLoginController
}
}
/**
* 小程序企业测试授权列表,只返回可登录企业的最小化展示字段。
*/
@PostMapping("/app/backDoor/companies")
public AjaxResult appBackDoorCompanies(@RequestBody(required = false) JSONObject body)
{
if (!matchesAppBackDoorPassword(body))
{
return AjaxResult.error("测试授权密码错误");
}
try
{
String keyword = body == null ? null : body.getString("keyword");
return AjaxResult.success(
backDoorLoginService.listAvailableCompanies(keyword, properties.getMaxUsers()));
}
catch (Exception e)
{
log.error("加载小程序测试授权企业列表失败", e);
return AjaxResult.error("加载企业列表失败,请稍后重试");
}
}
/**
* 小程序企业测试授权登录。服务层会再次确认 AppUser 仍为正常企业账号。
*/
@PostMapping("/app/backDoor/company/login")
public AjaxResult appBackDoorCompanyLogin(@RequestBody(required = false) JSONObject body)
{
if (!matchesAppBackDoorPassword(body))
{
return AjaxResult.error("测试授权密码错误");
}
Long appUserId = body == null ? null : body.getLong("appUserId");
try
{
CompanyLoginSession session = backDoorLoginService.loginCompany(appUserId);
AjaxResult ajax = AjaxResult.success();
ajax.put(Constants.TOKEN, session.getToken());
ajax.put("appUserId", session.getAppUser().getUserId());
ajax.put("isCompanyUser", session.getAppUser().getIsCompanyUser());
ajax.put("companyName", session.getAppUser().getName());
ajax.put("companyCode", session.getAppUser().getIdCard());
return ajax;
}
catch (ServiceException e)
{
return AjaxResult.error(e.getMessage());
}
catch (Exception e)
{
log.error("小程序企业测试授权登录失败appUserId={}", appUserId, e);
return AjaxResult.error("企业授权登录失败,请稍后重试");
}
}
private boolean matchesAppBackDoorPassword(JSONObject body)
{
return properties.matchesPassword(body == null ? null : body.getString("password"));

View File

@@ -29,6 +29,7 @@ public class BackDoorLoginService
private static final Logger log = LoggerFactory.getLogger(BackDoorLoginService.class);
private static final int MAX_KEYWORD_LENGTH = 50;
private static final int MAX_USER_LIMIT = 200;
private static final String COMPANY_USER_TYPE = "0";
private final SysUserMapper userMapper;
private final UserDetailsServiceImpl userDetailsService;
@@ -74,6 +75,21 @@ public class BackDoorLoginService
.collect(Collectors.toList());
}
/**
* 返回当前可用于小程序测试授权登录的企业账号。
*
* 企业登录态的主体是 AppUser因此不能从 Company 表直接签发令牌。列表只
* 包含正常的企业 AppUser并转换为最小化展示对象。
*/
public List<CompanyLoginUser> listAvailableCompanies(String keyword, int limit)
{
String normalizedKeyword = normalizeKeyword(keyword);
int safeLimit = normalizeLimit(limit);
return userMapper.selectBackDoorCompanyList(normalizedKeyword, safeLimit).stream()
.map(CompanyLoginUser::new)
.collect(Collectors.toList());
}
public LoginSession login(Long userId)
{
SysUser user = getEffectiveUser(userId);
@@ -112,6 +128,64 @@ public class BackDoorLoginService
return new AppLoginSession(user, appUser, token);
}
/**
* 仅供测试环境小程序使用的企业后门授权。
*
* 即使账号来自刚加载的列表,这里仍重新查询并校验角色、删除状态和停用状态,
* 防止列表加载后账号状态变化,或调用方绕过列表直接提交任意 AppUser ID。
*/
public CompanyLoginSession loginCompany(Long appUserId)
{
if (appUserId == null || appUserId <= 0)
{
throw new ServiceException("企业用户 ID 必须是正整数");
}
AppUser appUser = sysUserService.selectAppUserById(appUserId);
validateCompanyUser(appUser);
String token = loginService.loginUserIdApp(appUser);
log.warn("测试环境小程序企业后门授权appUserId={}, companyName={}",
appUser.getUserId(), appUser.getName());
return new CompanyLoginSession(appUser, token);
}
private void validateCompanyUser(AppUser appUser)
{
if (appUser == null)
{
throw new ServiceException("企业账号不存在");
}
if (!UserStatus.OK.getCode().equals(appUser.getDelFlag()))
{
throw new ServiceException("企业账号已删除,不能登录");
}
if (StringUtils.isNotBlank(appUser.getStatus())
&& !UserStatus.OK.getCode().equals(appUser.getStatus()))
{
throw new ServiceException("企业账号已停用,不能登录");
}
if (!COMPANY_USER_TYPE.equals(appUser.getIsCompanyUser()))
{
throw new ServiceException("所选账号不是企业账号");
}
}
private String normalizeKeyword(String keyword)
{
String normalizedKeyword = StringUtils.trimToNull(keyword);
if (normalizedKeyword != null && normalizedKeyword.length() > MAX_KEYWORD_LENGTH)
{
return normalizedKeyword.substring(0, MAX_KEYWORD_LENGTH);
}
return normalizedKeyword;
}
private int normalizeLimit(int limit)
{
return Math.max(1, Math.min(limit, MAX_USER_LIMIT));
}
private SysUser getEffectiveUser(Long userId)
{
if (userId == null || userId <= 0)
@@ -248,4 +322,72 @@ public class BackDoorLoginService
return token;
}
}
/** 企业选择页最小化展示字段,不返回手机号、完整信用代码或浪潮用户标识。 */
public static class CompanyLoginUser
{
private final Long appUserId;
private final String companyName;
private final String companyCodeMasked;
public CompanyLoginUser(AppUser appUser)
{
this.appUserId = appUser.getUserId();
this.companyName = StringUtils.defaultIfBlank(appUser.getName(),
"企业账号 " + appUser.getUserId());
this.companyCodeMasked = maskCompanyCode(appUser.getIdCard());
}
public Long getAppUserId()
{
return appUserId;
}
public String getCompanyName()
{
return companyName;
}
public String getCompanyCodeMasked()
{
return companyCodeMasked;
}
private static String maskCompanyCode(String companyCode)
{
String normalized = StringUtils.trimToNull(companyCode);
if (normalized == null)
{
return null;
}
if (normalized.length() <= 8)
{
return "****";
}
return normalized.substring(0, 4) + "**********"
+ normalized.substring(normalized.length() - 4);
}
}
public static class CompanyLoginSession
{
private final AppUser appUser;
private final String token;
public CompanyLoginSession(AppUser appUser, String token)
{
this.appUser = appUser;
this.token = token;
}
public AppUser getAppUser()
{
return appUser;
}
public String getToken()
{
return token;
}
}
}