Merge remote-tracking branch 'origin/V1.00' into V1.00
This commit is contained in:
commit
f8673ec1fb
30
src/main/java/com/cisd/tms/common/config/FilterConfig.java
Normal file
30
src/main/java/com/cisd/tms/common/config/FilterConfig.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.cisd.tms.common.config;
|
||||
|
||||
import com.cisd.tms.modules.device.filter.IpWhitelistFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class FilterConfig {
|
||||
|
||||
@Bean
|
||||
public IpWhitelistFilter ipWhitelistFilter() {
|
||||
return new IpWhitelistFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 Filter 并配置拦截规则
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<IpWhitelistFilter> ipWhitelistFilterRegistration() {
|
||||
FilterRegistrationBean<IpWhitelistFilter> registration = new FilterRegistrationBean<>();
|
||||
|
||||
registration.setFilter(ipWhitelistFilter());
|
||||
|
||||
//设置拦截路径
|
||||
registration.addUrlPatterns("/api/v1/*");
|
||||
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.cisd.tms.modules.device.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.cisd.tms.common.api.ApiResponse;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistResponse;
|
||||
import com.cisd.tms.modules.device.service.IpWhitelistService;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistRequest;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/device/whitelist")
|
||||
@Tag(name = "IP白名单管理", description = "提供IP白名单的增、删、改、查分页接口")
|
||||
public class IpWhitelistController {
|
||||
|
||||
@Autowired
|
||||
private IpWhitelistService ipWhitelistService;
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "添加IP白名单", description = "新增一条IP白名单记录")
|
||||
public ApiResponse<String> addWhitelist(@RequestBody IpWhitelistRequest req) {
|
||||
ipWhitelistService.addWhitelist(req);
|
||||
return ApiResponse.success("添加成功");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/update")
|
||||
@Operation(summary = "更新IP白名单", description = "根据ID更新IP白名单信息")
|
||||
public ApiResponse<String> updateWhitelist(@RequestBody IpWhitelistRequest req) {
|
||||
ipWhitelistService.updateWhitelist(req);
|
||||
return ApiResponse.success("更新成功");
|
||||
}
|
||||
|
||||
@PostMapping("/delete/{id}")
|
||||
@Operation(summary = "删除IP白名单", description = "根据ID删除指定IP白名单")
|
||||
public ApiResponse<String> deleteWhitelist(@PathVariable Long id) {
|
||||
ipWhitelistService.deleteWhitelist(id);
|
||||
return ApiResponse.success("删除成功");
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询IP白名单", description = "支持分页查询IP白名单列表")
|
||||
public ApiResponse<IPage<IpWhitelistResponse>> getWhitelistPage(@RequestBody IpWhitelistRequest req) {
|
||||
IPage<IpWhitelistResponse> page = ipWhitelistService.getWhitelistPage(req);
|
||||
return ApiResponse.success(page);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
package com.cisd.tms.modules.device.controller;
|
||||
|
||||
|
||||
import com.cisd.tms.common.api.ApiResponse;
|
||||
import com.cisd.tms.modules.device.dto.network.*;
|
||||
import com.cisd.tms.modules.device.service.NetworkConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "网络配置管理", description = "提供设备网络信息查询、IPv4/IPv6配置、Bond配置及路由管理等接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/device/network-config")
|
||||
public class NetworkConfigController {
|
||||
|
||||
private final NetworkConfigService networkConfigService;
|
||||
|
||||
public NetworkConfigController(NetworkConfigService networkConfigService){
|
||||
this.networkConfigService = networkConfigService;
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "获取网络信息", description = "获取当前设备的所有网络连接信息")
|
||||
@GetMapping("/network-info")
|
||||
public ApiResponse<List<NetworkInfoResponse>> getNetworkInfo(){
|
||||
return ApiResponse.success(networkConfigService.getNetworkInfo());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取IPv4配置信息", description = "根据设备名称获取指定网络接口的IPv4配置详情")
|
||||
@GetMapping("/ipv4-info/{deviceName}")
|
||||
public ApiResponse<Ipv4InfoResponse> getIpv4Info(@PathVariable String deviceName){
|
||||
return ApiResponse.success(networkConfigService.getIpv4Info(deviceName));
|
||||
}
|
||||
|
||||
@Operation(summary = "设置IPv4配置", description = "为指定网络接口配置IPv4地址、掩码、网关等信息")
|
||||
@PostMapping("/ipv4-config/set")
|
||||
public ApiResponse<String> setIpv4Config(@RequestBody Ipv4ConfigRequest req) {
|
||||
String resultMessage = networkConfigService.setIpv4Config(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取IPv6配置信息", description = "根据设备名称获取指定网络接口的IPv6配置详情")
|
||||
@GetMapping("/ipv6-info/{deviceName}")
|
||||
public ApiResponse<Ipv6InfoResponse> getIpv6Info(@PathVariable String deviceName){
|
||||
return ApiResponse.success(networkConfigService.getIpv6Info(deviceName));
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "设置IPv6配置", description = "为指定网络接口配置IPv6地址、前缀长度、网关等信息")
|
||||
@PostMapping("/ipv6-config/set")
|
||||
public ApiResponse<String> setIpv6Config(@RequestBody Ipv6ConfigRequest req) {
|
||||
String resultMessage = networkConfigService.setIpv6Config(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取所有Bond名称", description = "返回当前系统中所有已创建的Bond接口名称")
|
||||
@GetMapping("/all-bond-name")
|
||||
public ApiResponse<List<String>> getAllBondName(){
|
||||
return ApiResponse.success(networkConfigService.getAllBondName());
|
||||
}
|
||||
|
||||
@Operation(summary = "创建Bond", description = "创建一个新的Bond聚合接口,需指定名称、模式和从属接口")
|
||||
@PostMapping("/bond/create")
|
||||
public ApiResponse<String> createBond(@RequestBody BondCreateRequest req) {
|
||||
String resultMessage = networkConfigService.createBond(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "删除Bond", description = "根据Bond名称删除指定的聚合接口")
|
||||
@PostMapping("/bond/delete/{bondName}")
|
||||
public ApiResponse<String> deleteBond(@PathVariable("bondName") String bondName){
|
||||
String resultMessage = networkConfigService.deleteBond(bondName);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "添加从属接口到Bond", description = "向指定Bond中添加一个或多个从属网络接口")
|
||||
@PostMapping("/bond-slave/add")
|
||||
public ApiResponse<String> addSlavesTOBond(@RequestBody BondAddSlavesRequest req) {
|
||||
String resultMessage = networkConfigService.addSlavesTOBond(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "从Bond中移除从属接口", description = "从指定Bond中移除一个或多个从属网络接口")
|
||||
@PostMapping("/bond-slave/remove")
|
||||
public ApiResponse<String> removeSlaveFromBond(@RequestBody BondRemoveSlaveRequest req) {
|
||||
String resultMessage = networkConfigService.removeSlaveFromBond(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取Bond的从属接口列表", description = "根据Bond名称返回其所有从属接口名称")
|
||||
@GetMapping("/bond-slave/{bondName}")
|
||||
public ApiResponse<List<String>> getBondSlaves(@PathVariable String bondName){
|
||||
return ApiResponse.success(networkConfigService.getBondSlaves(bondName));
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "获取Bond模式", description = "根据Bond名称查询当前的绑定模式")
|
||||
@GetMapping("/bond/mode/{bondName}")
|
||||
public ApiResponse<String> getBondMode(@PathVariable("bondName") String bondName) {
|
||||
|
||||
String mode = networkConfigService.getBondMode(bondName);
|
||||
|
||||
if (mode == null) {
|
||||
return ApiResponse.fail(400, "未找到该连接的 Bond 模式", null);
|
||||
}
|
||||
|
||||
return ApiResponse.success(mode);
|
||||
}
|
||||
|
||||
@Operation(summary = "设置Bond模式", description = "修改指定Bond的绑定模式")
|
||||
@PostMapping("/bond/mode/set")
|
||||
public ApiResponse<String> setBondMode(@RequestBody BondModifyModeRequest req) {
|
||||
|
||||
String resultMessage = networkConfigService.setBondMode(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取路由表", description = "返回当前系统的IPv4/IPv6路由表信息")
|
||||
@GetMapping("/routes/routingTable")
|
||||
public ApiResponse<List<RouteInfoResponse>> getRoutingTable() {
|
||||
List<RouteInfoResponse> routes = networkConfigService.getRoutingTable();
|
||||
return ApiResponse.success(routes);
|
||||
}
|
||||
|
||||
@Operation(summary = "设置默认路由", description = "配置或修改系统的默认网关路由")
|
||||
@PostMapping("/routes/default/set")
|
||||
public ApiResponse<String> setDefaultRoute(@RequestBody SetDefaultRouteRequest req) {
|
||||
String resultMessage = networkConfigService.setDefaultRoute(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "添加静态路由", description = "新增一条静态路由规则")
|
||||
@PostMapping("/routes/static/add")
|
||||
public ApiResponse<String> addStaticRoute(@RequestBody AddStaticRouteRequest req) {
|
||||
String resultMessage = networkConfigService.addStaticRoute(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除默认路由", description = "删除指定的默认路由")
|
||||
@PostMapping("/routes/default/delete")
|
||||
public ApiResponse<String> deleteDefaultRoute(@RequestBody DeleteDefaultRouteRequest req) {
|
||||
String resultMessage = networkConfigService.deleteDefaultRoute(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除静态路由", description = "删除指定的静态路由")
|
||||
@PostMapping("/routes/static/delete")
|
||||
public ApiResponse<String> deleteStaticRoute(@RequestBody DeleteStaticRouteRequest req) {
|
||||
String resultMessage = networkConfigService.deleteStaticRoute(req);
|
||||
return ApiResponse.success(resultMessage);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "添加静态路由请求参数")
|
||||
public class AddStaticRouteRequest {
|
||||
|
||||
@Schema(description = "网络设备名称(如 eth0、bond0)", example = "eth0")
|
||||
private String deviceName;
|
||||
@Schema(description = "目标网络CIDR", example = "192.168.1.0/24")
|
||||
private String targetCidr;
|
||||
@Schema(description = "下一跳地址(网关IP)", example = "192.168.1.1")
|
||||
private String nextHop;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "向Bond添加从属接口请求参数")
|
||||
public class BondAddSlavesRequest {
|
||||
|
||||
@Schema(description = "Bond接口名称", example = "bond0")
|
||||
private String bondName;
|
||||
@Schema(description = "要添加到Bond的从属接口列表", example = "[\"eth0\", \"eth1\"]")
|
||||
private List<String> slaveList;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "创建Bond请求参数")
|
||||
public class BondCreateRequest {
|
||||
/**
|
||||
* Bond 名称,例如 "bond0"
|
||||
*/
|
||||
@Schema(description = "Bond 名称", example = "bond0")
|
||||
private String bondName;
|
||||
|
||||
/**
|
||||
* 模式 (例如: 0, 1, 2, 4)
|
||||
* 0: balance-rr (轮询)
|
||||
* 1: active-backup (主备)
|
||||
* 2: balance-xor
|
||||
* 4: 802.3ad (动态链路聚合)
|
||||
*/
|
||||
@Schema(description = "Bond 模式(0: balance-rr 轮询, 1: active-backup 主备, 2: balance-xor, 4: 802.3ad 动态链路聚合"
|
||||
,example = "1")
|
||||
private Integer mode;
|
||||
|
||||
/**
|
||||
* 可选的 IPv4 配置
|
||||
* 如果前端传了该对象,创建 Bond 后会自动配置 IP
|
||||
*/
|
||||
@Schema(description = "可选的 IPv4 配置,如果提供该对象,创建 Bond 后会自动配置 IP")
|
||||
private Ipv4ConfigRequest ipv4Config;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "修改bond模式请求参数")
|
||||
public class BondModifyModeRequest {
|
||||
|
||||
@Schema(description = "Bond 名称", example = "bond0")
|
||||
private String bondName;
|
||||
@Schema(description = "Bond 模式(0: balance-rr 轮询, 1: active-backup 主备, 2: balance-xor, 4: 802.3ad 动态链路聚合"
|
||||
,example = "1")
|
||||
private Integer mode;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "从Bond移除从属接口请求参数")
|
||||
public class BondRemoveSlaveRequest {
|
||||
|
||||
@Schema(description = "Bond接口名称", example = "bond0")
|
||||
private String bondName;
|
||||
@Schema(description = "要从Bond移除的从属接口列表", example = "[\"eth0\", \"eth1\"]")
|
||||
private List<String> slaveList;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "删除默认路由请求参数")
|
||||
public class DeleteDefaultRouteRequest {
|
||||
@Schema(description = "网络设备名称(如 eth0、bond0)", example = "eth0")
|
||||
private String deviceName;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "删除静态路由请求参数")
|
||||
public class DeleteStaticRouteRequest {
|
||||
|
||||
@Schema(description = "网络设备名称", example = "eth0")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "目标网络CIDR", example = "192.168.1.0/24")
|
||||
private String targetCidr;
|
||||
|
||||
@Schema(description = "下一跳地址(网关IP)", example = "192.168.1.1")
|
||||
private String nextHop;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IP白名单请求参数")
|
||||
public class IpWhitelistRequest {
|
||||
@Schema(description = "白名单记录ID(更新时必填)", example = "1")
|
||||
private String id;
|
||||
@Schema(description = "IP地址", example = "192.168.1.1")
|
||||
private String ip;
|
||||
@Schema(description = "掩码长度", example = "24")
|
||||
private String mask;
|
||||
|
||||
// 分页参数
|
||||
@Schema(description = "当前页码", defaultValue = "1", example = "1")
|
||||
private Integer pageNum = 1;
|
||||
@Schema(description = "每页条数", defaultValue = "10", example = "10")
|
||||
private Integer pageSize = 10;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IP白名单响应参数")
|
||||
public class IpWhitelistResponse {
|
||||
@Schema(description = "白名单记录ID(更新时必填)", example = "1")
|
||||
private String id;
|
||||
@Schema(description = "IP地址", example = "192.168.1.1")
|
||||
private String ip;
|
||||
@Schema(description = "掩码长度", example = "24")
|
||||
private String mask;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IPv4配置请求参数")
|
||||
public class Ipv4ConfigRequest {
|
||||
@Schema(description = "网络设备名称", example = "eth0")
|
||||
private String deviceName;
|
||||
@Schema(description = "IPv4地址", example = "192.168.1.100")
|
||||
private String ipv4;
|
||||
@Schema(description = "子网掩码长度", example = "24")
|
||||
private String maskLength;
|
||||
@Schema(description = "默认网关地址", example = "192.168.1.1")
|
||||
private String gateway;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IPv4配置信息响应")
|
||||
public class Ipv4InfoResponse {
|
||||
@Schema(description = "IPv4地址", example = "192.168.1.100")
|
||||
private String ipv4;
|
||||
@Schema(description = "子网掩码长度", example = "24")
|
||||
private String maskLength;
|
||||
@Schema(description = "默认网关地址", example = "192.168.1.1")
|
||||
private String gateway;
|
||||
@Schema(description = "IP获取方式(如 static、dhcp)", example = "static")
|
||||
private String method;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "单个IPv6地址及掩码")
|
||||
public class Ipv6AddressItem {
|
||||
@Schema(description = "IPv6地址", example = "2001:db8::2")
|
||||
private String ipv6;
|
||||
@Schema(description = "子网掩码前缀长度", example = "64")
|
||||
private String maskLength;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IPv6配置请求参数")
|
||||
public class Ipv6ConfigRequest {
|
||||
@Schema(description = "网络设备名称(如 eth0、bond0)", example = "eth0")
|
||||
private String deviceName;
|
||||
@Schema(description = "IPv6地址", example = "2001:db8::1")
|
||||
private String ipv6;
|
||||
@Schema(description = "默认网关地址", example = "2001:db8::1")
|
||||
private String gateway;
|
||||
@Schema(description = "子网前缀长度(如 64)", example = "64")
|
||||
private String maskLength;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "IPv6配置信息响应")
|
||||
public class Ipv6InfoResponse {
|
||||
@Schema(description = "IPv6地址及掩码列表")
|
||||
private List<Ipv6AddressItem> ipv6List;
|
||||
@Schema(description = "默认网关地址", example = "2001:db8::1")
|
||||
private String gateway;
|
||||
@Schema(description = "IP获取方式(如 static、dhcp、auto)", example = "static")
|
||||
private String method;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "网络接口信息响应参数")
|
||||
public class NetworkInfoResponse {
|
||||
|
||||
@Schema(description = "设备名称", example = "eth0")
|
||||
private String deviceName;
|
||||
@Schema(description = "接口类型", example = "ethernet")
|
||||
private String type;
|
||||
@Schema(description = "连接状态", example = "connected")
|
||||
private String state;
|
||||
@Schema(description = "NetworkManager中的连接名称(通常与deviceName相同)", example = "eth0")
|
||||
private String connectionName;
|
||||
@Schema(description = "IPv4 地址", example = "192.168.1.100")
|
||||
private String ipv4;
|
||||
@Schema(description = "IPv6 地址", example = "2001:db8::1")
|
||||
private List<String> ipv6;
|
||||
@Schema(description = "MAC 地址", example = "00:11:22:33:44:55")
|
||||
private String mac;
|
||||
@Schema(description = "默认网关地址", example = "192.168.1.1")
|
||||
private String gateway;
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "路由信息响应")
|
||||
public class RouteInfoResponse {
|
||||
|
||||
@Schema(description = "目标网络或主机(CIDR格式或主机地址)", example = "0.0.0.0/0")
|
||||
private String destination;
|
||||
|
||||
@Schema(description = "下一跳地址(网关)", example = "192.168.1.1")
|
||||
private String nextHop;
|
||||
|
||||
@Schema(description = "出口网络接口名称", example = "eth0")
|
||||
private String interfaceName;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.cisd.tms.modules.device.dto.network;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "设置默认路由请求参数")
|
||||
public class SetDefaultRouteRequest {
|
||||
|
||||
@Schema(description = "网络设备名称(如 eth0、bond0)", example = "eth0")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "默认网关IP地址", example = "192.168.1.1")
|
||||
private String gatewayIp;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.cisd.tms.modules.device.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("tms_access_whitelist")
|
||||
public class IpWhitelistEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 掩码长度
|
||||
*/
|
||||
private String mask;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
package com.cisd.tms.modules.device.filter;
|
||||
|
||||
import com.cisd.tms.modules.device.service.IpWhitelistService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class IpWhitelistFilter implements Filter {
|
||||
|
||||
@Autowired
|
||||
private IpWhitelistService ipWhitelistService;
|
||||
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
String clientIp = getClientIp(request);
|
||||
List<String> whitelist = ipWhitelistService.getAllIp();
|
||||
|
||||
// 空名单兜底
|
||||
if (whitelist == null || whitelist.isEmpty()) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int clientIpInt;
|
||||
try {
|
||||
clientIpInt = ipToInt(clientIp);
|
||||
} catch (IllegalArgumentException e) {
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().write("{\"code\": 403, \"msg\": \"非法的客户端 IP 格式,拒绝访问\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 白名单匹配
|
||||
boolean isAllowed = false;
|
||||
for (String cidr : whitelist) {
|
||||
try{
|
||||
String[] parts = cidr.split("/");
|
||||
String networkIp = parts[0];
|
||||
int maskLength = parts.length > 1 ? Integer.parseInt(parts[1]) : 32;
|
||||
|
||||
if (maskLength < 0 || maskLength > 32) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int networkIpInt = ipToInt(networkIp);
|
||||
|
||||
int mask = (maskLength == 0) ? 0 : (0xFFFFFFFF << (32 - maskLength));
|
||||
isAllowed = (networkIpInt & mask) == (clientIpInt & mask);
|
||||
if (isAllowed){
|
||||
break;
|
||||
}
|
||||
} catch (IllegalArgumentException e){
|
||||
log.error("数据库白名单{}该条规则解析异常,", cidr, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 默认拒绝
|
||||
if (!isAllowed) {
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().write("{\"code\": 403, \"msg\": \"非法访问:您的IP不在允许的白名单内\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String[] headers = {
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_CLIENT_IP",
|
||||
"HTTP_X_FORWARDED_FOR"
|
||||
};
|
||||
for (String header : headers) {
|
||||
String ip = request.getHeader(header);
|
||||
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.split(",")[0].trim();
|
||||
}
|
||||
}
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
|
||||
private int ipToInt(String ipAddress) {
|
||||
String[] octets = ipAddress.split("\\.");
|
||||
if (octets.length != 4) {
|
||||
throw new IllegalArgumentException("非法的 IPv4 地址: " + ipAddress);
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int octet = Integer.parseInt(octets[i]);
|
||||
if (octet < 0 || octet > 255) {
|
||||
throw new IllegalArgumentException("非法的 IPv4 地址段: " + octet);
|
||||
}
|
||||
result |= (octet << (24 - (8 * i)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.cisd.tms.modules.device.mapper;
|
||||
|
||||
import com.cisd.tms.infrastructure.persistence.mapper.BaseMapperX;
|
||||
import com.cisd.tms.modules.device.entity.IpWhitelistEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
@Mapper
|
||||
public interface IpWhitelistMapper extends BaseMapperX<IpWhitelistEntity> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.cisd.tms.modules.device.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistRequest;
|
||||
import com.cisd.tms.modules.device.entity.IpWhitelistEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface IpWhitelistRepository {
|
||||
|
||||
void addWhitelist(IpWhitelistEntity entity);
|
||||
|
||||
Optional<IpWhitelistEntity> findById(Long id);
|
||||
|
||||
void updateWhitelist(IpWhitelistEntity entity);
|
||||
|
||||
void deleteById(Long id);
|
||||
|
||||
boolean existsByIpAndMask(String ip, String mask, Long excludeId);
|
||||
|
||||
/**
|
||||
* 分页查询白名单
|
||||
*/
|
||||
Page<IpWhitelistEntity> selectPage(Page<IpWhitelistEntity> page, IpWhitelistRequest req);
|
||||
|
||||
/**
|
||||
* 查询所有白名单
|
||||
*/
|
||||
List<IpWhitelistEntity> selectAll();
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.cisd.tms.modules.device.repository.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistRequest;
|
||||
import com.cisd.tms.modules.device.entity.IpWhitelistEntity;
|
||||
import com.cisd.tms.modules.device.mapper.IpWhitelistMapper;
|
||||
import com.cisd.tms.modules.device.repository.IpWhitelistRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@Repository
|
||||
public class IpWhiltelistRepositoryImpl implements IpWhitelistRepository {
|
||||
|
||||
@Autowired
|
||||
private IpWhitelistMapper ipWhitelistMapper;
|
||||
|
||||
@Override
|
||||
public void addWhitelist(IpWhitelistEntity entity){
|
||||
ipWhitelistMapper.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IpWhitelistEntity> findById(Long id){
|
||||
return Optional.ofNullable(ipWhitelistMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWhitelist(IpWhitelistEntity entity){
|
||||
ipWhitelistMapper.updateById(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(Long id){
|
||||
ipWhitelistMapper.deleteById(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean existsByIpAndMask(String ip, String mask, Long excludeId) {
|
||||
LambdaQueryWrapper<IpWhitelistEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IpWhitelistEntity::getIp, ip)
|
||||
.eq(IpWhitelistEntity::getMask, mask);
|
||||
|
||||
if (excludeId != null) {
|
||||
wrapper.ne(IpWhitelistEntity::getId, excludeId);
|
||||
}
|
||||
return ipWhitelistMapper.exists(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<IpWhitelistEntity> selectPage(Page<IpWhitelistEntity> page, IpWhitelistRequest req) {
|
||||
// LambdaQueryWrapper<IpWhitelistEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
//
|
||||
// if (StringUtils.hasText(req.getIp())) {
|
||||
// wrapper.like(IpWhitelistEntity::getIp, req.getIp());
|
||||
// }
|
||||
// if (StringUtils.hasText(req.getMask())) {
|
||||
// wrapper.eq(IpWhitelistEntity::getMask, req.getMask());
|
||||
// }
|
||||
// wrapper.orderByDesc(IpWhitelistEntity::getCreateTime);
|
||||
|
||||
return ipWhitelistMapper.selectPage(page, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IpWhitelistEntity> selectAll() {
|
||||
return ipWhitelistMapper.selectList(null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
package com.cisd.tms.modules.device.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.cisd.tms.common.exception.BizException;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistRequest;
|
||||
import com.cisd.tms.modules.device.dto.network.IpWhitelistResponse;
|
||||
import com.cisd.tms.modules.device.entity.IpWhitelistEntity;
|
||||
import com.cisd.tms.modules.device.repository.IpWhitelistRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Service
|
||||
public class IpWhitelistService {
|
||||
|
||||
private final IpWhitelistRepository ipWhitelistRepository;
|
||||
|
||||
public IpWhitelistService(IpWhitelistRepository ipWhitelistRepository) {
|
||||
this.ipWhitelistRepository = ipWhitelistRepository;
|
||||
}
|
||||
|
||||
public void addWhitelist(IpWhitelistRequest req) {
|
||||
// 新增前校验 IP+掩码 是否已存在
|
||||
checkIpRule(req.getIp(), req.getMask(), null);
|
||||
|
||||
IpWhitelistEntity entity = new IpWhitelistEntity();
|
||||
String ip = req.getIp();
|
||||
String mask = req.getMask();
|
||||
|
||||
|
||||
entity.setIp(ip);
|
||||
entity.setMask(mask);
|
||||
|
||||
ipWhitelistRepository.addWhitelist(entity);
|
||||
}
|
||||
//
|
||||
public void updateWhitelist(IpWhitelistRequest req) {
|
||||
if (req.getId() == null || req.getId().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("ID should not be null");
|
||||
}
|
||||
|
||||
Long idLong = Long.valueOf(req.getId());
|
||||
checkIpRule(req.getIp(), req.getMask(), idLong);
|
||||
|
||||
Optional<IpWhitelistEntity> entityOpt = ipWhitelistRepository.findById(idLong);
|
||||
if (entityOpt.isEmpty()) {
|
||||
throw new BizException(404, "ID is not exist");
|
||||
}
|
||||
IpWhitelistEntity entity = entityOpt.get();
|
||||
|
||||
entity.setIp(req.getIp());
|
||||
entity.setMask(req.getMask());
|
||||
ipWhitelistRepository.updateWhitelist(entity);
|
||||
}
|
||||
|
||||
|
||||
public void deleteWhitelist(Long id) {
|
||||
Optional<IpWhitelistEntity> entityOpt = ipWhitelistRepository.findById(id);
|
||||
if (entityOpt.isEmpty()) {
|
||||
throw new BizException(404, "ID is not exist");
|
||||
}
|
||||
ipWhitelistRepository.deleteById(id);
|
||||
}
|
||||
|
||||
|
||||
public IPage<IpWhitelistResponse> getWhitelistPage(IpWhitelistRequest req) {
|
||||
Page<IpWhitelistEntity> page = new Page<>(req.getPageNum(), req.getPageSize());
|
||||
ipWhitelistRepository.selectPage(page, req);
|
||||
|
||||
|
||||
return page.convert(entity -> {
|
||||
IpWhitelistResponse response = new IpWhitelistResponse();
|
||||
response.setId(String.valueOf(entity.getId()));
|
||||
response.setIp(entity.getIp());
|
||||
response.setMask(entity.getMask());
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getAllIp() {
|
||||
// CIDR 格式
|
||||
return ipWhitelistRepository.selectAll().stream()
|
||||
.map(entity -> entity.getIp() + "/" + entity.getMask())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 IP+掩码是否已存在
|
||||
*/
|
||||
private void checkIpRule(String ip, String mask, Long excludeId) {
|
||||
if (ip == null || ip.isEmpty()){
|
||||
throw new IllegalArgumentException("ip is empty");
|
||||
}
|
||||
if (mask == null || mask.isEmpty()){
|
||||
throw new IllegalArgumentException("mask is empty");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
String[] octets = ip.split("\\.");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (octets.length != 4) {
|
||||
throw new IllegalArgumentException("非法的 IPv4 地址: " + ip);
|
||||
}
|
||||
|
||||
if (octets[i].length() > 1 && octets[i].startsWith("0")) {
|
||||
throw new IllegalArgumentException("IP 地址段不允许包含前导零: " + octets[i]);
|
||||
}
|
||||
|
||||
int octet = Integer.parseInt(octets[i]);
|
||||
if (octet < 0 || octet > 255) {
|
||||
throw new IllegalArgumentException("非法的 IPv4 地址段: " + octet);
|
||||
}
|
||||
}
|
||||
|
||||
int maskInt= Integer.parseInt(mask);
|
||||
if (maskInt < 0 || maskInt > 32) {
|
||||
throw new IllegalArgumentException("掩码范围需要在 0 到 32 之间");
|
||||
}
|
||||
|
||||
|
||||
if (ipWhitelistRepository.existsByIpAndMask(ip, mask, excludeId)) {
|
||||
throw new BizException(404, "已存在该 IP 和掩码配置");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user