diff --git a/src/main/java/com/ai/da/common/security/config/SecurityConfig.java b/src/main/java/com/ai/da/common/security/config/SecurityConfig.java index fe600140..773587c9 100644 --- a/src/main/java/com/ai/da/common/security/config/SecurityConfig.java +++ b/src/main/java/com/ai/da/common/security/config/SecurityConfig.java @@ -12,14 +12,11 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import javax.annotation.Resource; -import java.util.ArrayList; @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @@ -63,7 +60,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求 .anyRequest().authenticated()//其余所有的请求都需要认证 .and().headers().frameOptions().disable()// 防止iframe 造成跨域 - .and().x509().subjectPrincipalRegex("CN=(.*?)(?:,|$)").userDetailsService(userDetailsService()) .and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理 .accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略,全局异常会先于Security框架处理异常,全局异常已特殊处理) .and().formLogin().loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口 @@ -85,13 +81,4 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { handler.setPermissionEvaluator(userPermissionEvaluator); return handler; } - - @Bean - public UserDetailsService userDetailsService() { - return username -> { - // 这里可以根据用户名查找用户信息,例如从数据库中查询 - // 返回 UserDetails 对象 - return new User(username, "", new ArrayList<>()); - }; - } } 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..fcb1d8f7 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,7 +45,7 @@ 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/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew", "/api/third/party/existNoLoginRequired", "/api/python/chatStream", "/api/python/flush", 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 13b17c73..9cc7dd4c 100644 --- a/src/main/java/com/ai/da/controller/ThirdPartyController.java +++ b/src/main/java/com/ai/da/controller/ThirdPartyController.java @@ -62,8 +62,8 @@ 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") @@ -83,4 +83,18 @@ public class ThirdPartyController { 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)); + } } 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..99b8cb20 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 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,151 @@ 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" + + "                        "; + } + + 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; }