refactor: remove obsolete mk login surface

This commit is contained in:
waner 2026-03-30 16:22:01 +08:00
parent ba919b4aff
commit fbe23b8ecb
8 changed files with 6 additions and 535 deletions

View File

@ -61,10 +61,10 @@ public class WebMvcConfig implements WebMvcConfigurer {
.addPathPatterns("/api/**") .addPathPatterns("/api/**")
.excludePathPatterns( .excludePathPatterns(
"/api/v1/device/status", "/api/v1/device/status",
"/api/v1/auth/login",
"/api/v1/auth/password-login", "/api/v1/auth/password-login",
"/api/v1/auth/ukey-login", "/api/v1/auth/ukey-login",
"/api/v1/auth/ukey-login/randoms" "/api/v1/auth/ukey-login/randoms",
"/api/v1/auth/captcha"
); );
registry.addInterceptor(internalAuthorizationInterceptor) registry.addInterceptor(internalAuthorizationInterceptor)

View File

@ -1,52 +0,0 @@
package com.cisd.tms.modules.mk.config;
import com.cisd.tms.modules.mk.dto.UserInfo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ConfigurationProperties(prefix = "tms.ukey")
public class UKeyLoginProperties {
/**
* 认证信息白名单
*/
private List<UserInfo> authenticationInfoList = new ArrayList<>();
/**
* 角色密码映射
*/
private Map<String, String> rolePasswords = new HashMap<>();
/**
* IP 白名单文件路径
*/
private String whitelistPath;
public List<UserInfo> getAuthenticationInfoList() {
return authenticationInfoList;
}
public void setAuthenticationInfoList(List<UserInfo> authenticationInfoList) {
this.authenticationInfoList = authenticationInfoList;
}
public Map<String, String> getRolePasswords() {
return rolePasswords;
}
public void setRolePasswords(Map<String, String> rolePasswords) {
this.rolePasswords = rolePasswords;
}
public String getWhitelistPath() {
return whitelistPath;
}
public void setWhitelistPath(String whitelistPath) {
this.whitelistPath = whitelistPath;
}
}

View File

@ -1,32 +0,0 @@
package com.cisd.tms.modules.mk.controller;
import com.cisd.tms.common.api.ApiResponse;
import com.cisd.tms.modules.mk.dto.AuthInfo;
import com.cisd.tms.modules.mk.dto.LoginDTO;
import com.cisd.tms.modules.mk.service.UKeyLoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* UKey 登录接口迁移自 manager.service
*/
@RestController
@RequestMapping("/api/v1")
@Tag(name = "UKey 登录", description = "UKey 登录校验与认证信息生成")
public class LoginController {
@Resource
private UKeyLoginService uKeyLoginService;
@PostMapping("/UKeyLogin2")
@Operation(summary = "UKey 登录", description = "校验 UKey 签名、随机数与角色密码,并返回认证信息。")
public ApiResponse<AuthInfo> uKeyLogin(@RequestBody LoginDTO loginDTO, HttpServletRequest request) {
return ApiResponse.success(uKeyLoginService.uKeyLogin(loginDTO, request));
}
}

View File

@ -1,142 +0,0 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 登录时传输的实体
*/
@Data
public class LoginDTO {
/**
* 选择的角色
*/
private String roleSelected;
/**
* 登录的角色
*/
private String role;
/**
* 认证信息
*/
private List<LoginAuthInfo> authInfo;
/**
* 密码
*/
private String password;
public Set<String> getRids() {
Set<String> roles = new HashSet<>();
if (authInfo == null) {
return roles;
}
for (LoginAuthInfo auth : authInfo) {
roles.add(auth.rid);
}
return roles;
}
public List<String> getRandom() {
List<String> randomList = new ArrayList<>();
if (authInfo == null) {
return randomList;
}
for (LoginAuthInfo loginAuthInfo : authInfo) {
randomList.add(loginAuthInfo.getRb());
}
return randomList;
}
public UserInfo getUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setRole(this.role);
List<UserInfo.User> userList = new ArrayList<>();
if (authInfo != null) {
for (LoginAuthInfo loginAuthInfo : authInfo) {
UserInfo.User user = new UserInfo.User();
user.setUid(loginAuthInfo.getUid());
user.setRid(loginAuthInfo.getRid());
userList.add(user);
}
}
userInfo.setUser(userList);
return userInfo;
}
public List<UKeySignVerifyDTO> getUKeySignVerifyDTOList() {
List<UKeySignVerifyDTO> uKeySignVerifyDTOList = new ArrayList<>();
if (authInfo == null) {
return uKeySignVerifyDTOList;
}
for (LoginAuthInfo loginAuthInfo : authInfo) {
UKeySignVerifyDTO uKeySignVerifyDTO = new UKeySignVerifyDTO();
UKeySignDTO uKeySignDTO = new UKeySignDTO();
uKeySignDTO.setPubKey(loginAuthInfo.pubKey);
uKeySignDTO.setRole(this.role);
uKeySignDTO.setUid(loginAuthInfo.uid);
uKeySignDTO.setRid(loginAuthInfo.rid);
uKeySignVerifyDTO.setuKeySignDTO(uKeySignDTO);
uKeySignVerifyDTO.setSign(loginAuthInfo.issueSign);
uKeySignVerifyDTOList.add(uKeySignVerifyDTO);
}
return uKeySignVerifyDTOList;
}
public List<LoginSignDTO> getLoginSignDTOList() {
List<LoginSignDTO> loginSignDTOList = new ArrayList<>();
if (authInfo == null) {
return loginSignDTOList;
}
for (LoginAuthInfo loginAuthInfo : authInfo) {
LoginSignDTO loginSignDTO = new LoginSignDTO();
loginSignDTO.setPubKey(loginAuthInfo.pubKey);
loginSignDTO.setSignValue(loginAuthInfo.loginSign);
loginSignDTO.setLoginSignData(loginAuthInfo.loginSignData);
loginSignDTOList.add(loginSignDTO);
}
return loginSignDTOList;
}
@Data
public static class LoginAuthInfo {
/**
* U盾公钥
*/
private String pubKey;
/**
* U盾 uid
*/
private String uid;
/**
* U盾 rid
*/
private String rid;
/**
* 前端生成随机数
*/
private String ra;
/**
* 后端生成随机数
*/
private String rb;
/**
* 发行签名
*/
private String issueSign;
/**
* 登录签名的原始值
*/
private String loginSignData;
/**
* 登录签名
*/
private String loginSign;
}
}

View File

@ -1,40 +0,0 @@
package com.cisd.tms.modules.mk.dto;
public class LoginSignDTO {
/**
* U盾公钥
*/
private String pubKey;
/**
* 签名原始数据
*/
private String loginSignData;
/**
* 签名值
*/
private String signValue;
public String getPubKey() {
return pubKey;
}
public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}
public String getLoginSignData() {
return loginSignData;
}
public void setLoginSignData(String loginSignData) {
this.loginSignData = loginSignData;
}
public String getSignValue() {
return signValue;
}
public void setSignValue(String signValue) {
this.signValue = signValue;
}
}

View File

@ -1,70 +0,0 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 角色信息
*/
@Data
public class UserInfo {
/**
* 角色名称
*/
private String role;
private Integer defpassflag;
private List<User> user;
private List<String> permissions;
@Data
public static class User {
/**
* uid
*/
private String uid;
/**
* rid
*/
private String rid;
public boolean isSameUser(User user) {
return this.uid.equals(user.uid) && this.rid.equals(user.rid);
}
}
/**
* 认证信息校验校验配置文件中的认证信息和传入的认证信息是否相同
*/
public boolean roleUserAuth(List<UserInfo> authenticationInfoList) {
List<User> userConfig = new ArrayList<>(getUserFromAuthList(authenticationInfoList));
for (User current : this.user) {
Iterator<User> iterable = userConfig.iterator();
while (iterable.hasNext()) {
if (iterable.next().isSameUser(current)) {
iterable.remove();
break;
}
}
}
return userConfig.isEmpty();
}
/**
* 获取配置信息当中相应角色应包含的认证信息
*/
public List<User> getUserFromAuthList(List<UserInfo> authenticationInfoList) {
for (UserInfo authenticationInfo : authenticationInfoList) {
if (authenticationInfo.getRole().equals(this.role)) {
this.permissions = authenticationInfo.getPermissions();
return authenticationInfo.getUser();
}
}
throw new IllegalArgumentException("role info not found: " + role);
}
}

View File

@ -1,195 +0,0 @@
package com.cisd.tms.modules.mk.service;
import com.cisd.tms.common.util.IpWhitelistUtil;
import com.cisd.tms.common.util.Sm2SignatureUtil;
import com.cisd.tms.modules.mk.config.UKeyLoginProperties;
import com.cisd.tms.modules.mk.dto.AuthInfo;
import com.cisd.tms.modules.mk.dto.LoginDTO;
import com.cisd.tms.modules.mk.dto.LoginSignDTO;
import com.cisd.tms.modules.mk.dto.UKeySignEntity;
import com.cisd.tms.modules.mk.dto.UKeySignVerifyDTO;
import com.cisd.tms.modules.mk.dto.UserInfo;
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Service
public class UKeyLoginService {
private static final Logger log = LoggerFactory.getLogger(UKeyLoginService.class);
private final LmkService lmkService;
private final ObjectMapper objectMapper;
private final UKeyLoginProperties loginProperties;
private volatile List<String> randomList;
public UKeyLoginService(LmkService lmkService, ObjectMapper objectMapper, UKeyLoginProperties loginProperties) {
this.lmkService = lmkService;
this.objectMapper = objectMapper;
this.loginProperties = loginProperties;
}
public AuthInfo uKeyLogin(LoginDTO loginDTO, HttpServletRequest request) {
try {
log.info("UKey login payload: {}", objectMapper.writeValueAsString(loginDTO));
currentRoleCheck(loginDTO.getRole(), loginDTO.getRids());
uKeySignCheck(loginDTO.getUKeySignVerifyDTOList());
UserInfo userInfo = loginDTO.getUserInfo();
userInfoCheck(userInfo);
throwIfLmkNotGenerated();
randomCheck(loginDTO.getRandom());
loginSignCheck(loginDTO.getLoginSignDTOList());
whitelistCheck(request);
checkRolePassword(loginDTO.getRole(), loginDTO.getPassword());
AuthInfo authInfo = AuthInfo.getInstance(UUID.randomUUID().toString());
log.info("UKey login success, role={}", loginDTO.getRole());
return authInfo;
} catch (JsonProcessingException e) {
throw new IllegalStateException("serialize login payload failed", e);
} catch (RuntimeException e) {
log.error("UKey login failed: {}", e.getMessage(), e);
throw e;
}
}
private void currentRoleCheck(String role, java.util.Set<String> rids) {
boolean matched;
switch (role) {
case "superadmin" -> matched = rids.size() == 3
&& rids.contains("1")
&& rids.contains("2")
&& rids.contains("3");
case "keyadmin" -> matched = rids.size() == 2
&& rids.contains("4")
&& rids.contains("5");
case "auditadmin" -> matched = rids.size() == 1
&& rids.contains("6");
case "configadmin" -> matched = rids.size() == 1
&& rids.contains("7");
case "systemadmin" -> matched = rids.size() == 1
&& rids.contains("8");
default -> matched = false;
}
if (!matched) {
throw new IllegalArgumentException("selected role not matched with UKey rids");
}
}
private void uKeySignCheck(List<UKeySignVerifyDTO> uKeySignVerifyDTOList) {
String iPubKey = lmkService.exportIkPublicKeyHex();
boolean result = true;
for (UKeySignVerifyDTO uKeySignVerifyDTO : uKeySignVerifyDTOList) {
String payload;
try {
payload = objectMapper.writeValueAsString(UKeySignEntity.getInstance(
uKeySignVerifyDTO.getuKeySignDTO(), iPubKey));
} catch (JsonProcessingException e) {
throw new IllegalStateException("serialize ukey sign payload failed", e);
}
boolean verified = Sm2SignatureUtil.verifyBase64Signature(
uKeySignVerifyDTO.getuKeySignDTO().getPubKey(),
payload,
uKeySignVerifyDTO.getSign());
result = result && verified;
}
if (!result) {
throw new IllegalArgumentException("ukey issue sign verify failed");
}
}
private void userInfoCheck(UserInfo userInfo) {
List<UserInfo> config = loginProperties.getAuthenticationInfoList();
if (config == null || config.isEmpty()) {
throw new IllegalStateException("ukey authentication config missing");
}
boolean result = userInfo.roleUserAuth(config);
if (!result) {
throw new IllegalArgumentException("auth info incorrect");
}
}
private void throwIfLmkNotGenerated() {
int masterKeyCode = lmkService.getMasterKeyStatus().getCode();
if (MasterKeyStatus.ABNORMAL.getCode() == masterKeyCode) {
throw new IllegalStateException("master key not generated");
}
}
private void randomCheck(List<String> incomingRandoms) {
if (incomingRandoms == null || incomingRandoms.isEmpty()) {
throw new IllegalArgumentException("random number input error");
}
List<String> currentRandomList = this.randomList;
if (currentRandomList == null || currentRandomList.isEmpty()) {
throw new IllegalStateException("random list not initialized");
}
for (String r : incomingRandoms) {
if (!currentRandomList.contains(r)) {
throw new IllegalArgumentException("random number input error");
}
}
}
private void loginSignCheck(List<LoginSignDTO> loginSignDTOList) {
boolean result = true;
for (LoginSignDTO loginSignDTO : loginSignDTOList) {
boolean verified = Sm2SignatureUtil.verifyBase64Signature(
loginSignDTO.getPubKey(),
loginSignDTO.getLoginSignData(),
loginSignDTO.getSignValue());
result = result && verified;
}
if (!result) {
throw new IllegalArgumentException("login sign verify failed");
}
}
private void whitelistCheck(HttpServletRequest request) {
String clientIp = IpWhitelistUtil.getClientIp(request);
List<String> whitelist = IpWhitelistUtil.readWhitelist(resolveWhitelistPath());
if (!whitelist.isEmpty()) {
if (!IpWhitelistUtil.isIpInWhitelist(clientIp, whitelist)) {
throw new IllegalArgumentException("access denied");
}
}
}
private String resolveWhitelistPath() {
String configured = loginProperties.getWhitelistPath();
if (configured != null && !configured.isBlank()) {
return configured;
}
return System.getProperty("user.dir") + "/config/whitelist.txt";
}
private void checkRolePassword(String role, String password) {
Map<String, String> rolePasswords = loginProperties.getRolePasswords();
if (rolePasswords == null || rolePasswords.isEmpty()) {
throw new IllegalStateException("role password config missing");
}
String expected = rolePasswords.get(role);
if (expected == null) {
throw new IllegalArgumentException("role not found: " + role);
}
if (!expected.equals(password)) {
throw new IllegalArgumentException("password check failed");
}
}
public void setRandomList(List<String> randomList) {
this.randomList = randomList;
}
}

View File

@ -36,8 +36,10 @@ class TmsApplicationTests {
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"执行重置任务\""))) .andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"执行重置任务\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"/api/v1/files/upload\""))) .andExpect(content().string(org.hamcrest.Matchers.containsString("\"/api/v1/files/upload\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"上传初始化文件\""))) .andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"上传初始化文件\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"/api/v1/auth/login\""))) .andExpect(content().string(org.hamcrest.Matchers.containsString("\"/api/v1/auth/password-login\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"内部用户登录\""))); .andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"口令登录\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"/api/v1/auth/ukey-login\"")))
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"summary\":\"UKey 登录\"")));
} }
@Test @Test