feature: Support security for soruce and more

This commit is contained in:
qianmoQ 2022-10-20 22:37:44 +08:00
parent a8b7a75aa2
commit ff1644c8ad
24 changed files with 253 additions and 113 deletions

View File

@ -7,6 +7,7 @@ import io.edurt.datacap.server.entity.PluginAuditEntity;
import io.edurt.datacap.server.entity.SourceEntity;
import io.edurt.datacap.server.repository.PluginAuditRepository;
import io.edurt.datacap.server.repository.SourceRepository;
import io.edurt.datacap.server.security.UserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
@ -68,6 +69,7 @@ public class AuditPluginHandler
Optional<SourceEntity> sourceEntity = this.sourceRepository.findById(Long.valueOf(executeEntity.getName()));
pluginAudit.setPlugin(sourceEntity.get());
}
pluginAudit.setUser(UserDetailsService.getUser());
pluginAudit.setEndTime(Timestamp.valueOf(LocalDateTime.now()));
this.pluginAuditRepository.save(pluginAudit);
}

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.JwtResponse;
import io.edurt.datacap.server.common.Response;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.ExecuteEntity;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.FormatEntity;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller.admin;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.service.PluginAuditService;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.PageEntity;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller.admin;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.service.SourceService;

View File

@ -1,4 +1,4 @@
package io.edurt.datacap.server.controller;
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.PageEntity;

View File

@ -58,6 +58,12 @@ public class PluginAuditEntity
@JsonIncludeProperties(value = {"name", "type"})
private SourceEntity plugin;
// Add from 1.1.0.20221115
@ManyToOne
@JoinColumn(name = "user_id")
@JsonIncludeProperties(value = {"id", "username"})
private UserEntity user;
public void setEndTime(Timestamp endTime)
{
this.endTime = endTime;

View File

@ -1,6 +1,8 @@
package io.edurt.datacap.server.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.server.common.ProtocolEnum;
import io.edurt.datacap.server.validation.ValidationGroup;
@ -17,6 +19,8 @@ import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotEmpty;
@ -85,4 +89,14 @@ public class SourceEntity
@OneToMany(mappedBy = "plugin", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
@JsonIgnore
private List<PluginAuditEntity> pluginAudits;
// Add from 1.1.0.20221115
@Column(name = "public", columnDefinition = "boolean default false")
@JsonProperty(value = "public")
private Boolean publish; // Public use or not
@ManyToOne
@JoinColumn(name = "user_id")
@JsonIncludeProperties(value = {"id", "username"})
private UserEntity user;
}

View File

@ -1,5 +1,6 @@
package io.edurt.datacap.server.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.server.validation.ValidationGroup;
import lombok.AllArgsConstructor;
@ -7,6 +8,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
@ -16,6 +18,7 @@ import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotBlank;
@ -23,6 +26,7 @@ import javax.validation.constraints.Size;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Entity
@ -68,4 +72,8 @@ public class UserEntity
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<RoleEntity> roles = new HashSet<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
@JsonIgnore
private List<SourceEntity> sources;
}

View File

@ -1,9 +1,15 @@
package io.edurt.datacap.server.repository;
import io.edurt.datacap.server.entity.PluginAuditEntity;
import io.edurt.datacap.server.entity.UserEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface PluginAuditRepository
extends PagingAndSortingRepository<PluginAuditEntity, Long>
{
Page<PluginAuditEntity> findAllByUser(UserEntity user, Pageable pageable);
Long countByUser(UserEntity user);
}

View File

@ -1,10 +1,17 @@
package io.edurt.datacap.server.repository;
import io.edurt.datacap.server.entity.SourceEntity;
import io.edurt.datacap.server.entity.UserEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface SourceRepository
extends PagingAndSortingRepository<SourceEntity, Long>
{
SourceEntity findByName(String name);
Page<SourceEntity> findAllByUserOrPublishIsTrue(UserEntity user, Pageable pageable);
Long countByUserOrPublishIsTrue(UserEntity user);
}

View File

@ -2,12 +2,15 @@ package io.edurt.datacap.server.security;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.edurt.datacap.server.entity.UserEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class UserDetailsService
@ -86,4 +89,19 @@ public class UserDetailsService
{
return id;
}
public static UserEntity getUser()
{
UserEntity userInfo = new UserEntity();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (Objects.nonNull(authentication)) {
Object principal = authentication.getPrincipal();
if (Objects.nonNull(principal)) {
UserDetailsService loginPrincipalUserInfo = (UserDetailsService) principal;
userInfo.setUsername(loginPrincipalUserInfo.getUsername());
userInfo.setId(loginPrincipalUserInfo.getId());
}
}
return userInfo;
}
}

View File

@ -5,6 +5,7 @@ import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.PageEntity;
import io.edurt.datacap.server.entity.PluginAuditEntity;
import io.edurt.datacap.server.repository.PluginAuditRepository;
import io.edurt.datacap.server.security.UserDetailsService;
import io.edurt.datacap.server.service.PluginAuditService;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@ -24,12 +25,12 @@ public class PluginAuditServiceImpl
public Response<PageEntity<PluginAuditEntity>> getAll(int offset, int limit)
{
Pageable pageable = PageRequestAdapter.of(offset, limit);
return Response.success(PageEntity.build(this.pluginAuditRepository.findAll(pageable)));
return Response.success(PageEntity.build(this.pluginAuditRepository.findAllByUser(UserDetailsService.getUser(), pageable)));
}
@Override
public Response<Long> count()
{
return Response.success(this.pluginAuditRepository.count());
return Response.success(this.pluginAuditRepository.countByUser(UserDetailsService.getUser()));
}
}

View File

@ -10,7 +10,9 @@ import io.edurt.datacap.server.common.ServiceState;
import io.edurt.datacap.server.entity.PageEntity;
import io.edurt.datacap.server.entity.PluginEntity;
import io.edurt.datacap.server.entity.SourceEntity;
import io.edurt.datacap.server.entity.UserEntity;
import io.edurt.datacap.server.repository.SourceRepository;
import io.edurt.datacap.server.security.UserDetailsService;
import io.edurt.datacap.server.service.SourceService;
import io.edurt.datacap.spi.FormatType;
import io.edurt.datacap.spi.Plugin;
@ -40,6 +42,7 @@ public class SourceServiceImpl
@Override
public Response<SourceEntity> saveOrUpdate(SourceEntity configure)
{
configure.setUser(UserDetailsService.getUser());
return Response.success(this.sourceRepository.save(configure));
}
@ -47,7 +50,8 @@ public class SourceServiceImpl
public Response<PageEntity<SourceEntity>> getAll(int offset, int limit)
{
Pageable pageable = PageRequestAdapter.of(offset, limit);
return Response.success(PageEntity.build(this.sourceRepository.findAll(pageable)));
UserEntity user = UserDetailsService.getUser();
return Response.success(PageEntity.build(this.sourceRepository.findAllByUserOrPublishIsTrue(user, pageable)));
}
@Override
@ -109,6 +113,6 @@ public class SourceServiceImpl
@Override
public Response<Long> count()
{
return Response.success(this.sourceRepository.count());
return Response.success(this.sourceRepository.countByUserOrPublishIsTrue(UserDetailsService.getUser()));
}
}

View File

@ -36,3 +36,21 @@ CREATE TABLE IF NOT EXISTS `datacap`.`user_roles`
INSERT INTO `datacap`.`user_roles` (`user_id`, `role_id`)
VALUES (1, 1),
(2, 2);
ALTER TABLE `datacap`.`source`
ADD COLUMN `public` boolean default false;
-- Set the openness of the previous version to public
UPDATE `datacap`.`source`
SET `public` = true;
ALTER TABLE `datacap`.`source`
ADD COLUMN `user_id` bigint(20) NOT NULL;
-- Example Set the user of the previous version as the administrator
UPDATE `datacap`.`source`
SET `user_id` = 1;
ALTER TABLE `datacap`.`audit_plugin`
ADD COLUMN `user_id` bigint(20) NOT NULL;
-- Example Set the user of the previous version as the administrator
UPDATE `datacap`.`audit_plugin`
SET `user_id` = 1;

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.server.controller;
import io.edurt.datacap.server.BaseParamTest;
import io.edurt.datacap.server.common.JSON;
import io.edurt.datacap.server.controller.user.ExecuteController;
import io.edurt.datacap.server.entity.ExecuteEntity;
import io.edurt.datacap.spi.FormatType;
import lombok.extern.slf4j.Slf4j;

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.server.controller;
import io.edurt.datacap.server.BaseParamTest;
import io.edurt.datacap.server.common.JSON;
import io.edurt.datacap.server.controller.user.FormatController;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.server.controller;
import io.edurt.datacap.server.BaseParamTest;
import io.edurt.datacap.server.common.JSON;
import io.edurt.datacap.server.controller.user.SourceController;
import io.edurt.datacap.server.entity.SourceEntity;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;

View File

@ -10,5 +10,18 @@ export default {
logout: 'Logout',
english: 'English',
chinese: 'Chinese',
register: 'Register'
register: 'Register',
no: 'No',
name: 'Name',
description: 'Description',
protocol: 'protocol',
host: 'Host',
port: 'Port',
catalog: 'Catalog',
database: 'Database',
createTime: 'Create Time',
action: 'Action',
public: 'Public',
private: 'Private',
modify: 'Modify'
}

View File

@ -10,5 +10,18 @@ export default {
logout: '注销',
english: '英语',
chinese: '中文',
register: '注册'
register: '注册',
no: '编号',
name: '名称',
description: '描述',
protocol: '协议',
host: '主机',
port: '端口',
catalog: 'Catalog',
database: '数据库',
createTime: '创建时间',
action: '操作',
public: '公开',
private: '私有',
modify: '修改'
}

View File

@ -6,32 +6,36 @@
<template #title>Create new source</template>
<a-button type="primary" shape="circle" size="small" @click="handlerCreateOrUpdate()">
<template #icon>
<plus-circle-outlined />
<plus-circle-outlined/>
</template>
</a-button>
</a-tooltip>
</template>
<a-table size="middle" :loading="loading" :columns="headers" :data-source="columns" :pagination="pagination"
@change="handlerTableChange($event)">
@change="handlerTableChange($event)">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'public'">
<a-switch v-model:checked="record.public" disabled :checked-children="$t('common.public')" :un-checked-children="$t('common.private')"/>
</template>
<template v-if="column.dataIndex === 'action'">
<a-space style="width: 100%">
<a-popconfirm title="Are you sure delete?" ok-text="Yes" cancel-text="No"
@confirm="handlerDeleteRecord(record.id)">
@confirm="handlerDeleteRecord(record.id)">
<a-tooltip>
<template #title>Delete</template>
<a-button type="primary" danger shape="circle" size="small">
<template #icon>
<minus-outlined />
<minus-outlined/>
</template>
</a-button>
</a-tooltip>
</a-popconfirm>
<a-tooltip>
<template #title>Mofidy</template>
<template #title>{{ $t('common.modify') }}</template>
<a-button type="primary" shape="circle" size="small" @click="handlerCreateOrUpdate(record.id)">
<template #icon>
<edit-outlined />
<edit-outlined/>
</template>
</a-button>
</a-tooltip>
@ -42,24 +46,33 @@
</a-card>
<SourceInfoView v-if="visibleSourceInfo" :isVisible="visibleSourceInfo" :id="applyId"
@close="handlerCloseCreateNew($event)" />
@close="handlerCloseCreateNew($event)"/>
</div>
</template>
<script lang="ts">
import { SourceService } from "@/services/SourceService";
import { headers } from "@/views/pages/admin/source/SourceGenerate";
import {SourceService} from "@/services/SourceService";
import {createHeaders} from "@/views/pages/admin/source/SourceGenerate";
import SourceInfoView from "@/views/pages/admin/source/SourceInfo.vue";
import { MinusOutlined, PlusCircleOutlined } from '@ant-design/icons-vue';
import { message } from "ant-design-vue";
import { defineComponent } from "vue";
import {MinusOutlined, PlusCircleOutlined} from '@ant-design/icons-vue';
import {message} from "ant-design-vue";
import {defineComponent} from "vue";
import {useI18n} from 'vue-i18n';
export default defineComponent({
name: "SourceConsoleView",
components: { SourceInfoView, PlusCircleOutlined, MinusOutlined },
data() {
components: {SourceInfoView, PlusCircleOutlined, MinusOutlined},
setup()
{
const i18n = useI18n();
const headers = createHeaders(i18n);
return {
headers
}
},
data()
{
return {
headers,
columns: [],
loading: false,
visibleSourceInfo: false,
@ -74,11 +87,13 @@ export default defineComponent({
}
}
},
created() {
created()
{
this.handlerInitialize(this.pagination.current, this.pagination.pageSize)
},
methods: {
handlerInitialize(page: number, size: number) {
handlerInitialize(page: number, size: number)
{
this.loading = true;
new SourceService()
.getSources(page, size)
@ -90,18 +105,21 @@ export default defineComponent({
this.loading = false;
})
},
handlerCreateOrUpdate(value?: number) {
handlerCreateOrUpdate(value?: number)
{
if (value) {
this.applyId = value;
}
this.visibleSourceInfo = true;
},
handlerCloseCreateNew(value: boolean) {
handlerCloseCreateNew(value: boolean)
{
this.visibleSourceInfo = value;
this.applyId = 0;
this.handlerInitialize(this.pagination.current, this.pagination.pageSize);
},
handlerDeleteRecord(id: number) {
handlerDeleteRecord(id: number)
{
new SourceService()
.delete(id)
.then((response) => {
@ -111,7 +129,8 @@ export default defineComponent({
}
});
},
handlerTableChange(pagination: any) {
handlerTableChange(pagination: any)
{
this.pagination.current = pagination.current;
this.pagination.pageSize = pagination.pageSize;
this.handlerInitialize(pagination.current, pagination.pageSize)

View File

@ -1,4 +1,4 @@
import { SourceModel } from "@/model/SourceModel";
import {SourceModel} from "@/model/SourceModel";
const emptySource: SourceModel = {
name: "",
@ -13,85 +13,93 @@ const emptySource: SourceModel = {
type: ""
};
const headers = [
{
title: 'No',
name: 'id',
dataIndex: 'id',
key: 'id',
},
{
title: 'Name',
name: 'name',
dataIndex: 'name',
key: 'name',
ellipsis: true
},
{
title: 'Description',
name: 'description',
dataIndex: 'description',
key: 'description',
ellipsis: true
},
{
title: 'Protocol',
name: 'protocol',
dataIndex: 'protocol',
key: 'protocol',
ellipsis: true
},
{
title: 'Host',
name: 'host',
dataIndex: 'host',
key: 'host',
ellipsis: true
},
{
title: 'Port',
name: 'port',
dataIndex: 'port',
key: 'port',
ellipsis: true
},
{
title: 'User Name',
name: 'username',
dataIndex: 'username',
key: 'username',
ellipsis: true
},
{
title: 'Catalog',
name: 'catalog',
dataIndex: 'catalog',
key: 'catalog',
ellipsis: true
},
{
title: 'Database',
name: 'database',
dataIndex: 'database',
key: 'database',
ellipsis: true
},
{
title: 'Create Time',
name: 'createTime',
dataIndex: 'createTime',
key: 'createTime',
ellipsis: true
},
{
title: 'Action',
name: 'action',
dataIndex: 'action',
key: 'action'
}
];
const createHeaders = (i18n: any) => {
return [
{
title: i18n.t('common.no'),
name: 'id',
dataIndex: 'id',
key: 'id',
},
{
title: i18n.t('common.name'),
name: 'name',
dataIndex: 'name',
key: 'name',
ellipsis: true
},
{
title: i18n.t('common.description'),
name: 'description',
dataIndex: 'description',
key: 'description',
ellipsis: true
},
{
title: i18n.t('common.protocol'),
name: 'protocol',
dataIndex: 'protocol',
key: 'protocol',
ellipsis: true
},
{
title: i18n.t('common.host'),
name: 'host',
dataIndex: 'host',
key: 'host',
ellipsis: true
},
{
title: i18n.t('common.port'),
name: 'port',
dataIndex: 'port',
key: 'port',
ellipsis: true
},
{
title: i18n.t('common.username'),
name: 'username',
dataIndex: 'username',
key: 'username',
ellipsis: true
},
{
title: i18n.t('common.catalog'),
name: 'catalog',
dataIndex: 'catalog',
key: 'catalog',
ellipsis: true
},
{
title: i18n.t('common.database'),
name: 'database',
dataIndex: 'database',
key: 'database',
ellipsis: true
},
{
title: i18n.t('common.public'),
name: 'public',
dataIndex: 'public',
key: 'public'
},
{
title: i18n.t('common.createTime'),
name: 'createTime',
dataIndex: 'createTime',
key: 'createTime',
ellipsis: true
},
{
title: i18n.t('common.action'),
name: 'action',
dataIndex: 'action',
key: 'action'
}
];
};
export {
headers,
createHeaders,
emptySource
}