diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index 7974a487..c2625612 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -45,8 +45,8 @@ public class AuthenticationFilter extends OncePerRequestFilter { "/webjars/", "/swagger-resources", "/v2/api-docs", "api/account/resetPwd", "/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId", "/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile", - "/api/third/party/addNoLoginRequired","/api/third/party/deleteNoLoginRequired", - "/api/third/party/existNoLoginRequired", + "/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew", + "/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl", "/api/python/chatStream", "/api/python/flush", "/api/account/healthy" diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index d62d7335..1a91a5e5 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -144,9 +144,9 @@ public class AccountController { return Response.success(accountService.getExpiredTime()); } - @ApiOperation(value = "查询账号到期时间") + @ApiOperation(value = "免密登录") @PostMapping("/noLoginRequired") - public Response noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO){ - return Response.success(accountService.noLoginRequired(noLoginRequiredDTO)); + public Response noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request){ + return Response.success(accountService.noLoginRequired(noLoginRequiredDTO, request)); } } diff --git a/src/main/java/com/ai/da/controller/ThirdPartyController.java b/src/main/java/com/ai/da/controller/ThirdPartyController.java index 72167882..2572ed5b 100644 --- a/src/main/java/com/ai/da/controller/ThirdPartyController.java +++ b/src/main/java/com/ai/da/controller/ThirdPartyController.java @@ -7,11 +7,15 @@ import com.ai.da.service.AccountService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.security.cert.X509Certificate; @Api(tags = "Third Party Modules") @@ -59,7 +63,48 @@ public class ThirdPartyController { @CrossOrigin @ApiOperation(value = "add No Login Required") @PostMapping("/existNoLoginRequired") - public Response existNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO) { - return Response.success(accountService.existNoLoginRequired(noLoginRequiredDTO)); + public Response existNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + return Response.success(accountService.existNoLoginRequired(noLoginRequiredDTO, request)); + } + + @GetMapping("/your-secured-endpoint") +// @PreAuthorize("hasRole('ROLE_USER')") + public String securedEndpoint(HttpServletRequest request, @AuthenticationPrincipal PreAuthenticatedAuthenticationToken authenticationToken) { + // 从请求属性中获取证书 + X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); + if (certificates != null && certificates.length > 0) { + X509Certificate clientCertificate = certificates[0]; + // 可以从 clientCertificate 中获取证书信息,例如主题、颁发者等 + String subject = clientCertificate.getSubjectX500Principal().getName(); + String issuer = clientCertificate.getIssuerX500Principal().getName(); + // 处理逻辑 + return "Secured Endpoint. Client Subject: " + subject + ", Issuer: " + issuer; + } else { + // 证书不存在或获取失败 + return "Failed to retrieve client certificate."; + } + } + + @CrossOrigin + @ApiOperation(value = "add No Login Required") + @PostMapping("/addNoLoginRequiredNew") + public Response addNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + return Response.success(accountService.addNoLoginRequiredNew(noLoginRequiredDTO, request)); + } + + @CrossOrigin + @ApiOperation(value = "add No Login Required") + @PostMapping("/deleteNoLoginRequiredNew") + public Response deleteNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + return Response.success(accountService.deleteNoLoginRequiredNew(noLoginRequiredDTO, request)); + } + + @Value("${redirect_url}") + private String REDIRECT_URL; + @CrossOrigin + @ApiOperation(value = "add No Login Required") + @PostMapping("/getRedirectUrl") + public Response getRedirectUrl() { + return Response.success(REDIRECT_URL); } } diff --git a/src/main/java/com/ai/da/model/dto/NoLoginRequiredDTO.java b/src/main/java/com/ai/da/model/dto/NoLoginRequiredDTO.java index 661703fd..81d94583 100644 --- a/src/main/java/com/ai/da/model/dto/NoLoginRequiredDTO.java +++ b/src/main/java/com/ai/da/model/dto/NoLoginRequiredDTO.java @@ -5,4 +5,6 @@ import lombok.Data; @Data public class NoLoginRequiredDTO { private String browserIdentifiers; + private String id; + private Boolean deleteById; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index d6c7aede..86293174 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -120,7 +120,11 @@ public interface AccountService extends IService { Boolean deleteNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO); - AccountLoginVO noLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO); + AccountLoginVO noLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); - Boolean existNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO); + Boolean existNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); + + String addNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); + + Boolean deleteNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index f66a9369..97ad6bc6 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -647,12 +647,29 @@ public class AccountServiceImpl extends ServiceImpl impl @Override - public AccountLoginVO noLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO) { + public AccountLoginVO noLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + String id = noLoginRequiredDTO.getId(); + if (!isStringInRange(id)) { + throw new BusinessException("Illegal serial number!"); + } + // 获取真实 IP 地址,考虑了经过代理的情况 + String ipAddress = request.getHeader("X-Forwarded-For"); + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + } + String browserIdentifiers = ipAddress + "," + id; QueryWrapper qw = new QueryWrapper<>(); - qw.lambda().eq(Account::getBrowserIdentifiers, noLoginRequiredDTO.getBrowserIdentifiers()); + qw.lambda().eq(Account::getUserName, "PolyU-SFT-" + id); + qw.lambda().eq(Account::getBrowserIdentifiers, browserIdentifiers); List accountList = accountMapper.selectList(qw); if (CollectionUtil.isEmpty(accountList)) { - throw new BusinessException("This browser is not registered as login free"); + throw new BusinessException("Machine not registered or machine identification has changed, login free has failed, please contact us at help@aida.com.hk."); } Account account = accountList.get(0); AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); @@ -668,12 +685,152 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public Boolean existNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO) { + public Boolean existNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + String id = noLoginRequiredDTO.getId(); + // 获取真实 IP 地址,考虑了经过代理的情况 + String ipAddress = request.getHeader("X-Forwarded-For"); + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + } + String browserIdentifiers = ipAddress + "," + id; QueryWrapper qw = new QueryWrapper<>(); - qw.lambda().eq(Account::getBrowserIdentifiers, noLoginRequiredDTO.getBrowserIdentifiers()); + qw.lambda().eq(Account::getUserName, "PolyU-SFT-" + id); List accountList = accountMapper.selectList(qw); - if (CollectionUtil.isEmpty(accountList)) { - return Boolean.FALSE; + if (!CollectionUtil.isEmpty(accountList)) { + throw new BusinessException(""); + } + return Boolean.TRUE; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String addNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + // 验证机房注册序列号(001-100) + String id = noLoginRequiredDTO.getId(); + if (!isStringInRange(id)) { + throw new BusinessException("Illegal serial number."); + } + // 获取真实 IP 地址,考虑了经过代理的情况 + String ipAddress = request.getHeader("X-Forwarded-For"); + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + } + String browserIdentifiers = ipAddress + "," + id; + // 构建查询条件,查找已注册的账户数量 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(Account::getUserName, "PolyU-SFT-" + id); +// queryWrapper.lambda().eq(Account::getBrowserIdentifiers, browserIdentifiers); + List existingAccounts = accountMapper.selectList(queryWrapper); + + // 检查序列号是否被注册 + if (CollectionUtil.isNotEmpty(existingAccounts)) { + throw new BusinessException("The serial number has already been registered."); + } + + // 检查机器是否已经注册了别的序列号 + queryWrapper.clear(); + queryWrapper.lambda().like(Account::getBrowserIdentifiers, ipAddress); + List accountList = accountMapper.selectList(queryWrapper); + if (CollectionUtil.isNotEmpty(accountList)) { + throw new BusinessException("This machine has already been registered with serial number " + accountList.get(0).getUserName().split("-")[2]); + } + + // 创建新账户 + Account newAccount = new Account(); + newAccount.setUserName("PolyU-SFT-" + id); + newAccount.setUserPassword("Third-000000"); + newAccount.setValidStartTime(System.currentTimeMillis()); + newAccount.setValidEndTime(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000); + newAccount.setCreateDate(new Date()); + newAccount.setIsBeginner(1); + newAccount.setIsTrial(0); + newAccount.setBrowserIdentifiers(browserIdentifiers); + newAccount.setLanguage(Language.ENGLISH.name()); + + // 插入新账户 + accountMapper.insert(newAccount); + + return "\n" + + "                        \n" + + "                        \n" + + "                            \n" + + "                            \n" + + "                            Document\n" + + " \n" + + "                        \n" + + "                        \n" + + "                        \n" + + "                            \n" + + "                        "; + } + + public static boolean isStringInRange(String input) { + // 去除字符串两端的空格 + input = input.trim(); + + // 使用正则表达式检查是否是三位数字 + if (input.matches("\\d{3}")) { + // 将字符串转换为整数 + int number = Integer.parseInt(input); + + // 检查是否在指定范围内 + return number >= 1 && number <= 100; + } + + return false; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) { + // 获取真实 IP 地址,考虑了经过代理的情况 + String ipAddress = request.getHeader("X-Forwarded-For"); + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + } + // 删除将被注销的用户 + QueryWrapper queryWrapperDelete = new QueryWrapper<>(); + if (StringUtils.isNotBlank(noLoginRequiredDTO.getId()) && noLoginRequiredDTO.getDeleteById()) { + // 验证机房注册序列号(001-100) + String id = noLoginRequiredDTO.getId(); + if (!isStringInRange(id)) { + throw new BusinessException("Illegal serial number."); + } + queryWrapperDelete.lambda().eq(Account::getUserName, "PolyU-SFT-" + noLoginRequiredDTO.getId()); + }else { + queryWrapperDelete.lambda().like(Account::getBrowserIdentifiers, ipAddress); + } + List accountList = accountMapper.selectList(queryWrapperDelete); + if (CollectionUtil.isNotEmpty(accountList)) { + for (Account account : accountList) { + //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效 + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + LocalCacheUtils.delTokenCache(String.valueOf(account.getId())); + } + accountMapper.deleteById(account.getId()); + // TODO:注销时删除用户数据,workspace,like,library等 + } } return Boolean.TRUE; } diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index a2f7a528..4c401b7d 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -64,3 +64,4 @@ minio.bucketName.results=aida-results minio.bucketName.sysImage=aida-sys-image minio.bucketName.users=aida-users minio.bucketName.collectionElement=aida-collection-element +redirect_url=http://18.167.251.121:7788