✨ feat: 添加小程序企业测试授权功能及相关接口
This commit is contained in:
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user