mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-11-01 18:51:45 +08:00
feat:优化攻击日志查询
This commit is contained in:
@@ -1 +1 @@
|
||||
docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20231126 -X SamWaf/global.GWAF_RELEASE_VERSION=v1.0.125 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64 main.go
|
||||
docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20231127 -X SamWaf/global.GWAF_RELEASE_VERSION=v1.0.126 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64 main.go
|
||||
@@ -61,74 +61,79 @@
|
||||
wafanalysisdaycountryrange
|
||||
} from '@/apis/stats';
|
||||
echarts.use([TooltipComponent, LegendComponent, PieChart, GridComponent, LineChart, CanvasRenderer, MapChart, VisualMapComponent]);
|
||||
import 'echarts-wordcloud';
|
||||
import 'echarts-wordcloud';
|
||||
|
||||
export default {
|
||||
name: 'Analysis',
|
||||
data() {
|
||||
return {
|
||||
//词云的相关配置
|
||||
wordCloudChartsInfo:{
|
||||
wordCloudEchart:null,
|
||||
wordCloudOptions:{
|
||||
series: [{
|
||||
type: 'wordCloud',
|
||||
shape: 'circle',
|
||||
keepAspect: false,
|
||||
// maskImage: maskImage,
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
width: '100%',
|
||||
height: '90%',
|
||||
right: null,
|
||||
bottom: null,
|
||||
sizeRange: [12, 60],
|
||||
rotationRange: [-90, 90],
|
||||
rotationStep: 45,
|
||||
gridSize: 8,
|
||||
drawOutOfBound: false,
|
||||
layoutAnimation: true,
|
||||
wordCloudChartsInfo: {
|
||||
wordCloudEchart: null,
|
||||
wordCloudOptions: {
|
||||
series: [{
|
||||
type: 'wordCloud',
|
||||
shape: 'circle',
|
||||
keepAspect: false,
|
||||
// maskImage: maskImage,
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
width: '100%',
|
||||
height: '90%',
|
||||
right: null,
|
||||
bottom: null,
|
||||
sizeRange: [12, 60],
|
||||
rotationRange: [-90, 90],
|
||||
rotationStep: 45,
|
||||
gridSize: 8,
|
||||
drawOutOfBound: false,
|
||||
layoutAnimation: true,
|
||||
textStyle: {
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: 'bold',
|
||||
color: function () {
|
||||
return 'rgb(' + [
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160)
|
||||
].join(',') + ')';
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
// focus: 'self',
|
||||
textStyle: {
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: 'bold',
|
||||
color: function () {
|
||||
return 'rgb(' + [
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160)
|
||||
].join(',') + ')';
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
// focus: 'self',
|
||||
textStyle: {
|
||||
textShadowBlur: 3,
|
||||
textShadowColor: '#333'
|
||||
}
|
||||
},
|
||||
//data属性中的value值却大,权重就却大,展示字体就却大
|
||||
data: [
|
||||
//{name: 'Farrah',value: 366},
|
||||
//{name: "汽车",value: 900},
|
||||
//{name: "视频",value: 606},
|
||||
]
|
||||
textShadowBlur: 3,
|
||||
textShadowColor: '#333'
|
||||
}
|
||||
},
|
||||
//data属性中的value值却大,权重就却大,展示字体就却大
|
||||
data: [
|
||||
//{name: 'Farrah',value: 366},
|
||||
//{name: "汽车",value: 900},
|
||||
//{name: "视频",value: 606},
|
||||
]
|
||||
}]
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
currentAction: "",
|
||||
action_options: [{
|
||||
label: '阻止',
|
||||
value: '阻止'
|
||||
},
|
||||
{
|
||||
label: '放行',
|
||||
value: '放行'
|
||||
},
|
||||
{
|
||||
label: '禁止',
|
||||
value: '禁止'
|
||||
},
|
||||
action_options: [
|
||||
{
|
||||
label: '全部',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '阻止',
|
||||
value: '阻止'
|
||||
},
|
||||
{
|
||||
label: '放行',
|
||||
value: '放行'
|
||||
},
|
||||
{
|
||||
label: '禁止',
|
||||
value: '禁止'
|
||||
},
|
||||
],
|
||||
presets: {
|
||||
最近7天: [new Date(+new Date() - 86400000 * 6), new Date()],
|
||||
@@ -217,6 +222,11 @@ import 'echarts-wordcloud';
|
||||
this.initEcharts();
|
||||
this.loadCountryData();
|
||||
},
|
||||
created() {
|
||||
this.range1[0] = LAST_7_DAYS[0]
|
||||
this.range1[1] = LAST_7_DAYS[1]
|
||||
console.log(this.range1)
|
||||
},
|
||||
|
||||
methods: {
|
||||
renderIcon() {
|
||||
@@ -272,7 +282,7 @@ import 'echarts-wordcloud';
|
||||
this.initWordCloud();
|
||||
},
|
||||
//初始化世界地图
|
||||
initWorldMap(){
|
||||
initWorldMap() {
|
||||
//
|
||||
/*
|
||||
融合数据 世界和中国
|
||||
@@ -313,16 +323,16 @@ import 'echarts-wordcloud';
|
||||
}); */
|
||||
},
|
||||
//初始化词云
|
||||
initWordCloud(){
|
||||
let that = this
|
||||
let echartDom = document.getElementById('wordCloudCountry')
|
||||
that.wordCloudChartsInfo.wordCloudEchart = echarts.init(echartDom)
|
||||
that.wordCloudChartsInfo.wordCloudEchart.setOption(that.wordCloudChartsInfo.wordCloudOptions)
|
||||
initWordCloud() {
|
||||
let that = this
|
||||
let echartDom = document.getElementById('wordCloudCountry')
|
||||
that.wordCloudChartsInfo.wordCloudEchart = echarts.init(echartDom)
|
||||
that.wordCloudChartsInfo.wordCloudEchart.setOption(that.wordCloudChartsInfo.wordCloudOptions)
|
||||
|
||||
//随着屏幕大小调节图表
|
||||
window.addEventListener("resize", () => {
|
||||
that.wordCloudChartsInfo.wordCloudEchart.resize();
|
||||
});
|
||||
//随着屏幕大小调节图表
|
||||
window.addEventListener("resize", () => {
|
||||
that.wordCloudChartsInfo.wordCloudEchart.resize();
|
||||
});
|
||||
},
|
||||
map_decodePolygon(coordinate, encodeOffsets, encodeScale) {
|
||||
var result = [];
|
||||
@@ -398,7 +408,7 @@ import 'echarts-wordcloud';
|
||||
width: 80%;
|
||||
height: 100vh;
|
||||
/* 让布局占据整个视口高度 */
|
||||
height:50rem;
|
||||
height: 50rem;
|
||||
}
|
||||
|
||||
.left-column {
|
||||
@@ -434,4 +444,4 @@ import 'echarts-wordcloud';
|
||||
/* 下半部分背景色 */
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -3,21 +3,14 @@
|
||||
|
||||
<t-card class="list-card-container">
|
||||
<t-row justify="space-between">
|
||||
<t-form
|
||||
ref="form"
|
||||
:data="searchformData"
|
||||
:label-width="80"
|
||||
colon
|
||||
:style="{ marginBottom: '8px' }"
|
||||
>
|
||||
<t-form ref="form" :data="searchformData" :label-width="80" colon :style="{ marginBottom: '8px' }">
|
||||
<t-row>
|
||||
<t-col :span="10">
|
||||
<t-row :gutter="[16, 24]">
|
||||
<t-col :flex="1">
|
||||
<t-form-item label="网站" name="rule">
|
||||
<t-select v-model="searchformData.host_code" clearable :style="{ width: '150px' }">
|
||||
<t-option v-for="(item, index) in host_dic" :value="index" :label="item"
|
||||
:key="index">
|
||||
<t-option v-for="(item, index) in host_dic" :value="index" :label="item" :key="index">
|
||||
{{ item }}
|
||||
</t-option>
|
||||
</t-select>
|
||||
@@ -26,50 +19,43 @@
|
||||
<t-col :flex="1">
|
||||
|
||||
<t-form-item label="规则名称" name="rule">
|
||||
<t-input
|
||||
v-model="searchformData.rule"
|
||||
class="form-item-content"
|
||||
type="search"
|
||||
placeholder="请输入规则名称"
|
||||
:style="{ minWidth: '134px' }"
|
||||
/>
|
||||
<t-input v-model="searchformData.rule" class="form-item-content" type="search" placeholder="请输入规则名称"
|
||||
:style="{ minWidth: '134px' }" />
|
||||
</t-form-item>
|
||||
</t-col>
|
||||
<t-col :flex="1">
|
||||
<t-form-item label="访问状态" name="action">
|
||||
<t-select
|
||||
v-model="searchformData.action"
|
||||
class="form-item-content`"
|
||||
:options="action_options"
|
||||
placeholder="请选择防御状态" :style="{ width: '100px' }"
|
||||
/>
|
||||
<t-select v-model="searchformData.action" class="form-item-content`" :options="action_options"
|
||||
placeholder="请选择防御状态" :style="{ width: '100px' }" />
|
||||
</t-form-item>
|
||||
</t-col>
|
||||
<t-col :flex="1">
|
||||
<t-form-item label="响应码" name="status_code">
|
||||
<t-input
|
||||
v-model="searchformData.status_code"
|
||||
class="form-item-content"
|
||||
placeholder="请输入响应码"
|
||||
:style="{ minWidth: '100px' }"
|
||||
/>
|
||||
<t-input v-model="searchformData.status_code" class="form-item-content" placeholder="请输入响应码"
|
||||
:style="{ minWidth: '100px' }" />
|
||||
</t-form-item>
|
||||
</t-col>
|
||||
<t-col :flex="1">
|
||||
<t-form-item label="访问IP" name="src_ip">
|
||||
<t-input
|
||||
v-model="searchformData.src_ip"
|
||||
class="form-item-content"
|
||||
placeholder="请输入访问IP"
|
||||
:style="{ minWidth: '100px' }"
|
||||
/>
|
||||
<t-input v-model="searchformData.src_ip" class="form-item-content" placeholder="请输入访问IP"
|
||||
:style="{ minWidth: '100px' }" />
|
||||
</t-form-item>
|
||||
</t-col>
|
||||
<t-col :flex="2">
|
||||
<t-form-item label="访问日期" name="unix_add_time">
|
||||
<t-date-range-picker v-model="range1" :presets="presets" enable-time-picker /></t-form-item>
|
||||
</t-col>
|
||||
<t-col :flex="1">
|
||||
<t-form-item label="访问方法" name="method">
|
||||
<t-select v-model="searchformData.method" class="form-item-content`" :options="method_options"
|
||||
placeholder="请输入访问方法" :style="{ width: '100px' }" />
|
||||
</t-form-item>
|
||||
</t-col>
|
||||
</t-row>
|
||||
</t-col>
|
||||
|
||||
<t-col :span="2" class="operation-container">
|
||||
<t-button theme="primary" :style="{ marginLeft: '8px' }" @click="getList('all')"> 查询 </t-button>
|
||||
<t-button theme="primary" :style="{ marginLeft: '8px' }" @click="getList('all')"> 查询 </t-button>
|
||||
<t-button type="reset" variant="base" theme="default"> 重置 </t-button>
|
||||
</t-col>
|
||||
</t-row>
|
||||
@@ -77,365 +63,470 @@
|
||||
</t-row>
|
||||
|
||||
<div class="table-container">
|
||||
<t-table
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
size="small"
|
||||
:rowKey="rowKey"
|
||||
:verticalAlign="verticalAlign"
|
||||
:pagination="pagination"
|
||||
:selected-row-keys="selectedRowKeys"
|
||||
:loading="dataLoading"
|
||||
@page-change="rehandlePageChange"
|
||||
@change="rehandleChange"
|
||||
@select-change="rehandleSelectChange"
|
||||
:headerAffixProps="{ offsetTop: offsetTop, container: getContainer }"
|
||||
>
|
||||
<!-- 按钮操作区域 -->
|
||||
<!-- <t-space direction="vertical">
|
||||
<t-space>
|
||||
<t-checkbox v-model="customText" style="margin-left: 16px">自定义列配置按钮</t-checkbox>
|
||||
</t-space>
|
||||
</t-space> -->
|
||||
<t-table :columns="columns" :data="data" size="small" :rowKey="rowKey" :verticalAlign="verticalAlign"
|
||||
:column-controller="columnControllerConfig" :displayColumns.sync="displayColumns" :pagination="pagination"
|
||||
:selected-row-keys="selectedRowKeys" :loading="dataLoading" @page-change="rehandlePageChange"
|
||||
@change="rehandleChange" @select-change="rehandleSelectChange"
|
||||
:headerAffixProps="{ offsetTop: offsetTop, container: getContainer }">
|
||||
|
||||
<template #action="{ row }">
|
||||
<t-tag v-if="row.action === '放行'" shape="round" theme="success" >{{row.action}}</t-tag>
|
||||
<t-tag v-if="row.action === '阻止'" shape="round" theme="danger" >{{row.action}}</t-tag>
|
||||
<t-tag v-if="row.action === '禁止'" shape="round" theme="warning" >{{row.action}}</t-tag>
|
||||
<template #action="{ row }">
|
||||
<t-tag v-if="row.action === '放行'" shape="round" theme="success">{{row.action}}</t-tag>
|
||||
<t-tag v-if="row.action === '阻止'" shape="round" theme="danger">{{row.action}}</t-tag>
|
||||
<t-tag v-if="row.action === '禁止'" shape="round" theme="warning">{{row.action}}</t-tag>
|
||||
|
||||
</template>
|
||||
<template #rule="{ row }">
|
||||
<t-tag v-if="row.rule !== ''" shape="round" theme="primary" variant="outline">{{row.rule}}</t-tag>
|
||||
</template>
|
||||
<template #country="{ row }">
|
||||
{{row.src_ip }} ({{row.country }}{{row.province }}{{row.city }})
|
||||
</template>
|
||||
<t-tag v-if="row.rule !== ''" shape="round" theme="primary" variant="outline">{{row.rule}}</t-tag>
|
||||
</template>
|
||||
<template #op="slotProps">
|
||||
<a class="t-button-link" @click="handleClickIPDetail(slotProps)">查询IP</a>
|
||||
<a class="t-button-link" @click="handleClickDetail(slotProps)">详情</a>
|
||||
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
||||
<!-- <a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a> -->
|
||||
</template>
|
||||
</t-table>
|
||||
</div>
|
||||
</t-card>
|
||||
<t-dialog
|
||||
header="确认删除当前所选合同?"
|
||||
:body="confirmBody"
|
||||
:visible.sync="confirmVisible"
|
||||
@confirm="onConfirmDelete"
|
||||
:onCancel="onCancel"
|
||||
>
|
||||
<t-dialog header="确认删除当前所选日志?" :body="confirmBody" :visible.sync="confirmVisible" @confirm="onConfirmDelete"
|
||||
:onCancel="onCancel">
|
||||
</t-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { SearchIcon } from 'tdesign-icons-vue';
|
||||
import Trend from '@/components/trend/index.vue';
|
||||
import { prefix } from '@/config/global';
|
||||
import {attacklogList} from '@/apis/waflog/attacklog';
|
||||
import Vue from 'vue';
|
||||
import { SearchIcon } from 'tdesign-icons-vue';
|
||||
import Trend from '@/components/trend/index.vue';
|
||||
import { prefix } from '@/config/global';
|
||||
import { attacklogList } from '@/apis/waflog/attacklog';
|
||||
|
||||
import { NowDate, ConvertStringToUnix, ConvertDateToString } from '@/utils/date';
|
||||
import {
|
||||
allhost
|
||||
} from '@/apis/host';
|
||||
|
||||
import { CONTRACT_STATUS, CONTRACT_STATUS_OPTIONS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
|
||||
import { ErrorCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-vue';
|
||||
import { CONTRACT_STATUS, CONTRACT_STATUS_OPTIONS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
|
||||
import { ErrorCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-vue';
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'ListBase',
|
||||
components: {
|
||||
SearchIcon,
|
||||
Trend,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
action_options: [{
|
||||
label: '阻止',
|
||||
value: '阻止'
|
||||
},
|
||||
{
|
||||
label: '放行',
|
||||
value: '放行'
|
||||
},
|
||||
{
|
||||
label: '禁止',
|
||||
value: '禁止'
|
||||
},
|
||||
],
|
||||
CONTRACT_STATUS,
|
||||
CONTRACT_STATUS_OPTIONS,
|
||||
CONTRACT_TYPES,
|
||||
CONTRACT_PAYMENT_TYPES,
|
||||
prefix,
|
||||
dataLoading: false,
|
||||
data: [],
|
||||
selectedRowKeys: [],
|
||||
value: 'first',
|
||||
columns: [
|
||||
{
|
||||
title: '状态',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
colKey: 'action',
|
||||
},
|
||||
{
|
||||
title: '触发规则',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'rule',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
width: 170,
|
||||
ellipsis: true,
|
||||
colKey: 'create_time',
|
||||
},
|
||||
{
|
||||
title: '域名',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'host',
|
||||
},
|
||||
const staticColumn = ['action', 'op'];
|
||||
|
||||
{
|
||||
title: '请求',
|
||||
width: 70,
|
||||
ellipsis: true,
|
||||
colKey: 'method',
|
||||
},
|
||||
{
|
||||
title: '来源IP',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'country',
|
||||
},
|
||||
{
|
||||
title: '访问url',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
colKey: 'url',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
width: 200,
|
||||
colKey: 'op',
|
||||
title: '操作',
|
||||
},
|
||||
],
|
||||
rowKey: 'REQ_UUID',
|
||||
tableLayout: 'auto',
|
||||
verticalAlign: 'top',
|
||||
hover: true,
|
||||
rowClassName: (rowKey: string) => `${rowKey}-class`,
|
||||
// 与pagination对齐
|
||||
pagination: {
|
||||
total: 0,
|
||||
current: 1,
|
||||
pageSize:10
|
||||
},
|
||||
searchValue: '',
|
||||
confirmVisible: false,
|
||||
deleteIdx: -1,
|
||||
//顶部搜索
|
||||
searchformData:{
|
||||
rule:"",
|
||||
action:"",
|
||||
src_ip:"",
|
||||
host_code:"",
|
||||
status_code:""
|
||||
},
|
||||
//主机字典
|
||||
host_dic:{}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
confirmBody() {
|
||||
if (this.deleteIdx > -1) {
|
||||
const { name } = this.data?.[this.deleteIdx];
|
||||
return `删除后,${name}的所有合同信息将被清空,且无法恢复`;
|
||||
}
|
||||
return '';
|
||||
const GROUP_COLUMNS = [
|
||||
{
|
||||
label: '正常维度',
|
||||
value: 'index',
|
||||
columns: ['action', 'rule', 'create_time'],
|
||||
},
|
||||
offsetTop() {
|
||||
return this.$store.state.setting.isUseTabsRouter ? 48 : 0;
|
||||
{
|
||||
label: '次要维度',
|
||||
value: 'secondary',
|
||||
columns: ['action', 'rule', 'create_time'],
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
console.log("attack list mounted ");
|
||||
if(this.$route.query.action != null){
|
||||
{
|
||||
label: '数据维度',
|
||||
value: 'data',
|
||||
columns: ['action', 'rule', 'create_time'],
|
||||
},
|
||||
];
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'ListBase',
|
||||
components: {
|
||||
SearchIcon,
|
||||
Trend,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
presets: {
|
||||
最近300天: [ConvertDateToString(new Date(+new Date() - 86400000 * 299)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
|
||||
最近7天: [ConvertDateToString(new Date(+new Date() - 86400000 * 6)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
|
||||
最近3天: [ConvertDateToString(new Date(+new Date() - 86400000 * 2)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
|
||||
今天: [ConvertDateToString(new Date()) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
|
||||
},
|
||||
range1: ['2023-11-01 00:00:00', '2023-11-16 23:59:59'],
|
||||
action_options: [
|
||||
{
|
||||
label: '全部',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '阻止',
|
||||
value: '阻止'
|
||||
},
|
||||
{
|
||||
label: '放行',
|
||||
value: '放行'
|
||||
},
|
||||
{
|
||||
label: '禁止',
|
||||
value: '禁止'
|
||||
},
|
||||
],
|
||||
method_options: [
|
||||
{
|
||||
label: '全部',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: 'POST',
|
||||
value: 'POST'
|
||||
},
|
||||
{
|
||||
label: 'GET',
|
||||
value: 'GET'
|
||||
},
|
||||
{
|
||||
label: 'CONNECT',
|
||||
value: 'CONNECT'
|
||||
}
|
||||
,
|
||||
{
|
||||
label: 'HEAD',
|
||||
value: 'HEAD'
|
||||
},
|
||||
{
|
||||
label: 'OPTIONS',
|
||||
value: 'OPTIONS'
|
||||
},
|
||||
{
|
||||
label: 'PRI',
|
||||
value: 'PRI'
|
||||
}
|
||||
],
|
||||
CONTRACT_STATUS,
|
||||
CONTRACT_STATUS_OPTIONS,
|
||||
CONTRACT_TYPES,
|
||||
CONTRACT_PAYMENT_TYPES,
|
||||
prefix,
|
||||
dataLoading: false,
|
||||
data: [],
|
||||
selectedRowKeys: [],
|
||||
value: 'first',
|
||||
customText: false,
|
||||
displayColumns: staticColumn.concat(['create_time','host','method','url','src_ip','country']),
|
||||
columns: [
|
||||
{
|
||||
title: '状态',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
colKey: 'action',
|
||||
},
|
||||
{
|
||||
title: '触发规则',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'rule',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
width: 170,
|
||||
ellipsis: true,
|
||||
colKey: 'create_time',
|
||||
},
|
||||
{
|
||||
title: '域名',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'host',
|
||||
},
|
||||
|
||||
{
|
||||
title: '请求',
|
||||
width: 70,
|
||||
ellipsis: true,
|
||||
colKey: 'method',
|
||||
},
|
||||
{
|
||||
title: '来源IP',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
colKey: 'src_ip',
|
||||
},
|
||||
{
|
||||
title: '国家',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
colKey: 'country',
|
||||
},
|
||||
{
|
||||
title: '省份',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
colKey: 'province',
|
||||
},{
|
||||
title: '城市',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
colKey: 'city',
|
||||
},
|
||||
{
|
||||
title: '访问url',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
colKey: 'url',
|
||||
},
|
||||
{
|
||||
title: 'Header',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
colKey: 'header',
|
||||
},
|
||||
{
|
||||
title: 'status',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
colKey: 'status',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
width: 200,
|
||||
colKey: 'op',
|
||||
title: '操作',
|
||||
},
|
||||
],
|
||||
rowKey: 'REQ_UUID',
|
||||
tableLayout: 'auto',
|
||||
verticalAlign: 'top',
|
||||
hover: true,
|
||||
rowClassName: (rowKey : string) => `${rowKey}-class`,
|
||||
// 与pagination对齐
|
||||
pagination: {
|
||||
total: 0,
|
||||
current: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
searchValue: '',
|
||||
confirmVisible: false,
|
||||
deleteIdx: -1,
|
||||
//顶部搜索
|
||||
searchformData: {
|
||||
rule: "",
|
||||
action: "",
|
||||
src_ip: "",
|
||||
host_code: "",
|
||||
status_code: "",
|
||||
method: "",
|
||||
},
|
||||
//主机字典
|
||||
host_dic: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
confirmBody() {
|
||||
if (this.deleteIdx > -1) {
|
||||
const { name } = this.data?.[this.deleteIdx];
|
||||
return `删除后,${name}的所有合同信息将被清空,且无法恢复`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
offsetTop() {
|
||||
return this.$store.state.setting.isUseTabsRouter ? 48 : 0;
|
||||
},
|
||||
columnControllerConfig() {
|
||||
return {
|
||||
placement: this.placement,
|
||||
fields: ['action', 'rule', 'create_time', 'host', 'method', 'url', 'header','country','province','city','status'],
|
||||
// 弹框组件属性透传
|
||||
dialogProps: { preventScrollThrough: true },
|
||||
// 列配置按钮属性头像
|
||||
buttonProps: this.customText ? { content: '显示列控制', theme: 'primary', variant: 'base' } : undefined,
|
||||
// 数据字段分组显示
|
||||
groupColumns: this.groupColumn ? GROUP_COLUMNS : undefined,
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
console.log(NowDate)
|
||||
this.range1[0] = NowDate + " 00:00:00"
|
||||
this.range1[1] = NowDate + " 23:59:59"
|
||||
console.log(this.range1)
|
||||
},
|
||||
mounted() {
|
||||
console.log("attack list mounted ");
|
||||
if (this.$route.query.action != null) {
|
||||
console.log(this.$route.query.action)
|
||||
this.searchformData.action = this.$route.query.action
|
||||
}
|
||||
// 判断 vuex 中是否有保存的搜索参数
|
||||
}
|
||||
// 判断 vuex 中是否有保存的搜索参数
|
||||
|
||||
if (this.$store.state.attacklog.msgData) {
|
||||
const attack = this.$store.state.attacklog;
|
||||
this.pagination.current = attack.msgData.currentpage;
|
||||
this.searchformData = attack.msgData.searchData; // 可以直接取出整个对象
|
||||
}
|
||||
if (this.$store.state.attacklog.msgData) {
|
||||
const attack = this.$store.state.attacklog;
|
||||
this.pagination.current = attack.msgData.currentpage;
|
||||
this.searchformData = attack.msgData.searchData; // 可以直接取出整个对象
|
||||
}
|
||||
|
||||
this.loadHostList()
|
||||
this.getList("")
|
||||
},
|
||||
watch: {
|
||||
'$route.query.action'(newVal, oldVal) {
|
||||
console.log('action changed', newVal, oldVal)
|
||||
this.searchformData.action = newVal
|
||||
this.loadHostList()
|
||||
this.getList("")
|
||||
},
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
console.log("attack list beforeRouteLeave ");
|
||||
// vuex 存储操作
|
||||
this.$store.dispatch("attacklog/setAttackMsgData", {
|
||||
//query: this.queryParam,
|
||||
currentpage: this.pagination.current,
|
||||
searchData: this.searchformData,
|
||||
})
|
||||
next(); // 继续后续的导航解析过程
|
||||
},
|
||||
methods: {
|
||||
loadHostList(){
|
||||
let that = this;
|
||||
allhost().then((res) => {
|
||||
let resdata = res
|
||||
console.log(resdata)
|
||||
if (resdata.code === 0) {
|
||||
let host_options = resdata.data;
|
||||
for(let i = 0;i<host_options.length;i++){
|
||||
that.host_dic[host_options[i].value] = host_options[i].label
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.log(e);
|
||||
})
|
||||
watch: {
|
||||
'$route.query.action'(newVal, oldVal) {
|
||||
console.log('action changed', newVal, oldVal)
|
||||
this.searchformData.action = newVal
|
||||
this.getList("")
|
||||
},
|
||||
},
|
||||
getList(keyword){
|
||||
|
||||
let that = this
|
||||
if(keyword!=undefined && keyword=="all"){
|
||||
that.pagination.current = 1
|
||||
}
|
||||
this.$request
|
||||
.post('/waflog/attack/list', {
|
||||
pageSize: that.pagination.pageSize,
|
||||
pageIndex: that.pagination.current,
|
||||
...that.searchformData
|
||||
},
|
||||
)
|
||||
.then((res) => {
|
||||
beforeRouteLeave(to, from, next) {
|
||||
console.log("attack list beforeRouteLeave ");
|
||||
// vuex 存储操作
|
||||
this.$store.dispatch("attacklog/setAttackMsgData", {
|
||||
//query: this.queryParam,
|
||||
currentpage: this.pagination.current,
|
||||
searchData: this.searchformData,
|
||||
})
|
||||
next(); // 继续后续的导航解析过程
|
||||
},
|
||||
methods: {
|
||||
loadHostList() {
|
||||
let that = this;
|
||||
allhost().then((res) => {
|
||||
let resdata = res
|
||||
console.log(resdata)
|
||||
if (resdata.code === 0) {
|
||||
|
||||
//const { list = [] } = resdata.data.list;
|
||||
|
||||
this.data = resdata.data.list;
|
||||
this.pagination = {
|
||||
...this.pagination,
|
||||
total: resdata.data.total,
|
||||
};
|
||||
let host_options = resdata.data;
|
||||
for (let i = 0; i < host_options.length; i++) {
|
||||
that.host_dic[host_options[i].value] = host_options[i].label
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.log(e);
|
||||
})
|
||||
.finally(() => {
|
||||
this.dataLoading = false;
|
||||
});
|
||||
this.dataLoading = true;
|
||||
},
|
||||
getContainer() {
|
||||
return document.querySelector('.tdesign-starter-layout');
|
||||
},
|
||||
rehandlePageChange(curr, pageInfo) {
|
||||
console.log('分页变化', curr, pageInfo);
|
||||
this.pagination.current = curr.current
|
||||
if(this.pagination.pageSize != curr.pageSize){
|
||||
.catch((e : Error) => {
|
||||
console.log(e);
|
||||
})
|
||||
},
|
||||
getList(keyword) {
|
||||
|
||||
let that = this
|
||||
if (keyword != undefined && keyword == "all") {
|
||||
that.pagination.current = 1
|
||||
}
|
||||
this.$request
|
||||
.post('/waflog/attack/list', {
|
||||
pageSize: that.pagination.pageSize,
|
||||
pageIndex: that.pagination.current,
|
||||
unix_add_time_begin: ConvertStringToUnix(this.range1[0]).toString(),
|
||||
unix_add_time_end: ConvertStringToUnix(this.range1[1]).toString(),
|
||||
...that.searchformData
|
||||
},
|
||||
)
|
||||
.then((res) => {
|
||||
let resdata = res
|
||||
console.log(resdata)
|
||||
if (resdata.code === 0) {
|
||||
|
||||
//const { list = [] } = resdata.data.list;
|
||||
|
||||
this.data = resdata.data.list;
|
||||
this.pagination = {
|
||||
...this.pagination,
|
||||
total: resdata.data.total,
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch((e : Error) => {
|
||||
console.log(e);
|
||||
})
|
||||
.finally(() => {
|
||||
this.dataLoading = false;
|
||||
});
|
||||
this.dataLoading = true;
|
||||
},
|
||||
getContainer() {
|
||||
return document.querySelector('.tdesign-starter-layout');
|
||||
},
|
||||
rehandlePageChange(curr, pageInfo) {
|
||||
console.log('分页变化', curr, pageInfo);
|
||||
this.pagination.current = curr.current
|
||||
if (this.pagination.pageSize != curr.pageSize) {
|
||||
this.pagination.current = 1
|
||||
this.pagination.pageSize = curr.pageSize
|
||||
}
|
||||
this.getList("")
|
||||
},
|
||||
rehandleSelectChange(selectedRowKeys: number[]) {
|
||||
this.selectedRowKeys = selectedRowKeys;
|
||||
},
|
||||
rehandleChange(changeParams, triggerAndData) {
|
||||
console.log('统一Change', changeParams, triggerAndData);
|
||||
},
|
||||
handleClickDetail(e) {
|
||||
console.log(e)
|
||||
const { req_uuid } = e.row
|
||||
console.log(req_uuid)
|
||||
this.$router.push(
|
||||
{
|
||||
path:'/waf/wafattacklogdetail',
|
||||
query: {
|
||||
req_uuid: req_uuid,
|
||||
},
|
||||
}
|
||||
this.getList("")
|
||||
},
|
||||
);
|
||||
},
|
||||
handleClickIPDetail(e) {
|
||||
console.log(e)
|
||||
const { src_ip } = e.row
|
||||
this.searchformData.src_ip = src_ip
|
||||
this.getList("")
|
||||
rehandleSelectChange(selectedRowKeys : number[]) {
|
||||
this.selectedRowKeys = selectedRowKeys;
|
||||
},
|
||||
rehandleChange(changeParams, triggerAndData) {
|
||||
console.log('统一Change', changeParams, triggerAndData);
|
||||
},
|
||||
handleClickDetail(e) {
|
||||
console.log(e)
|
||||
const { req_uuid } = e.row
|
||||
console.log(req_uuid)
|
||||
this.$router.push(
|
||||
{
|
||||
path: '/waf/wafattacklogdetail',
|
||||
query: {
|
||||
req_uuid: req_uuid,
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
handleClickIPDetail(e) {
|
||||
console.log(e)
|
||||
const { src_ip } = e.row
|
||||
this.searchformData.src_ip = src_ip
|
||||
this.getList("")
|
||||
|
||||
},
|
||||
handleClickDelete(row : { rowIndex : any }) {
|
||||
this.deleteIdx = row.rowIndex;
|
||||
this.confirmVisible = true;
|
||||
},
|
||||
onConfirmDelete() {
|
||||
// 真实业务请发起请求
|
||||
this.data.splice(this.deleteIdx, 1);
|
||||
this.pagination.total = this.data.length;
|
||||
const selectedIdx = this.selectedRowKeys.indexOf(this.deleteIdx);
|
||||
if (selectedIdx > -1) {
|
||||
this.selectedRowKeys.splice(selectedIdx, 1);
|
||||
}
|
||||
this.confirmVisible = false;
|
||||
this.$message.success('删除成功');
|
||||
this.resetIdx();
|
||||
},
|
||||
onCancel() {
|
||||
this.resetIdx();
|
||||
},
|
||||
resetIdx() {
|
||||
this.deleteIdx = -1;
|
||||
},
|
||||
},
|
||||
handleClickDelete(row: { rowIndex: any }) {
|
||||
this.deleteIdx = row.rowIndex;
|
||||
this.confirmVisible = true;
|
||||
},
|
||||
onConfirmDelete() {
|
||||
// 真实业务请发起请求
|
||||
this.data.splice(this.deleteIdx, 1);
|
||||
this.pagination.total = this.data.length;
|
||||
const selectedIdx = this.selectedRowKeys.indexOf(this.deleteIdx);
|
||||
if (selectedIdx > -1) {
|
||||
this.selectedRowKeys.splice(selectedIdx, 1);
|
||||
}
|
||||
this.confirmVisible = false;
|
||||
this.$message.success('删除成功');
|
||||
this.resetIdx();
|
||||
},
|
||||
onCancel() {
|
||||
this.resetIdx();
|
||||
},
|
||||
resetIdx() {
|
||||
this.deleteIdx = -1;
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '@/style/variables';
|
||||
@import '@/style/variables';
|
||||
|
||||
.payment-col {
|
||||
display: flex;
|
||||
|
||||
.trend-container {
|
||||
.payment-col {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 8px;
|
||||
|
||||
.trend-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left-operation-container {
|
||||
padding: 0 0 6px 0;
|
||||
margin-bottom: 16px;
|
||||
.left-operation-container {
|
||||
padding: 0 0 6px 0;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.selected-count {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
color: var(--td-text-color-secondary);
|
||||
.selected-count {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 360px;
|
||||
}
|
||||
.search-input {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.t-button + .t-button {
|
||||
.t-button+.t-button {
|
||||
margin-left: @spacer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,9 +5,20 @@ export const LAST_7_DAYS = [
|
||||
dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
|
||||
dayjs().format('YYYY-MM-DD'),
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const LAST_30_DAYS = [
|
||||
dayjs().subtract(30, 'day').format('YYYY-MM-DD'),
|
||||
dayjs().subtract(1, 'day').format('YYYY-MM-DD'),
|
||||
];
|
||||
//当前日期
|
||||
export const NowDate = dayjs().format('YYYY-MM-DD');
|
||||
|
||||
//转换数据成毫秒
|
||||
export function ConvertStringToUnix(timestr: string) :Number{
|
||||
return dayjs(timestr).valueOf()
|
||||
}
|
||||
//转换字符串
|
||||
export function ConvertDateToString(now: Date) :string{
|
||||
return dayjs(now).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package request
|
||||
import "SamWaf/model/common/request"
|
||||
|
||||
type WafAttackLogSearch struct {
|
||||
HostCode string `json:"host_code" form:"host_code"` //主机码
|
||||
Rule string `json:"rule" form:"rule"` //规则名
|
||||
Action string `json:"action" form:"action"` //状态
|
||||
SrcIp string `json:"src_ip" form:"src_ip"` //请求IP
|
||||
StatusCode string `json:"status_code" form:"status_code"` //响应码
|
||||
HostCode string `json:"host_code" form:"host_code"` //主机码
|
||||
Rule string `json:"rule" form:"rule"` //规则名
|
||||
Action string `json:"action" form:"action"` //状态
|
||||
SrcIp string `json:"src_ip" form:"src_ip"` //请求IP
|
||||
StatusCode string `json:"status_code" form:"status_code"` //响应码
|
||||
UnixAddTimeBegin string `json:"unix_add_time_begin" form:"unix_add_time_begin"` //开始时间
|
||||
UnixAddTimeEnd string `json:"unix_add_time_end" form:"unix_add_time_end"` //结束时间
|
||||
Method string `json:"method" form:"method"` //访问方法
|
||||
request.PageInfo
|
||||
}
|
||||
|
||||
@@ -34,14 +34,15 @@ func (receiver *WafLogService) GetListApi(log request.WafAttackLogSearch) ([]inn
|
||||
Action: log.Action,
|
||||
SrcIp: log.SrcIp,
|
||||
StatusCode: log.StatusCode,
|
||||
Method: log.Method,
|
||||
PageInfo: request2.PageInfo{
|
||||
PageIndex: 0,
|
||||
PageSize: 0,
|
||||
Keyword: "",
|
||||
},
|
||||
}
|
||||
global.GWAF_LOCAL_LOG_DB.Limit(log.PageSize).Where(whereCondition).Offset(log.PageSize * (log.PageIndex - 1)).Order("create_time desc").Find(&weblogs)
|
||||
global.GWAF_LOCAL_LOG_DB.Model(&innerbean.WebLog{}).Where(whereCondition).Count(&total)
|
||||
global.GWAF_LOCAL_LOG_DB.Limit(log.PageSize).Where(whereCondition).Where("unix_add_time>=? and unix_add_time<=?", log.UnixAddTimeBegin, log.UnixAddTimeEnd).Offset(log.PageSize * (log.PageIndex - 1)).Order("create_time desc").Find(&weblogs)
|
||||
global.GWAF_LOCAL_LOG_DB.Model(&innerbean.WebLog{}).Where(whereCondition).Where("unix_add_time>=? and unix_add_time<=?", log.UnixAddTimeBegin, log.UnixAddTimeEnd).Count(&total)
|
||||
return weblogs, total, nil
|
||||
}
|
||||
func (receiver *WafLogService) GetListByHostCodeApi(log request.WafAttackLogSearch) ([]innerbean.WebLog, int64, error) {
|
||||
|
||||
Vendored
+2
-2
@@ -6,8 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<title>Sam网站应用级入侵防御系统后台(Web Application Firewall)</title>
|
||||
<script type="module" crossorigin src="./assets/index.3ebd5785.js"></script>
|
||||
<link rel="stylesheet" href="./assets/style.caefab01.css">
|
||||
<script type="module" crossorigin src="./assets/index.bdd9c8b0.js"></script>
|
||||
<link rel="stylesheet" href="./assets/style.2e845f6b.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user