diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/CoreShareTicket.java b/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/CoreShareTicket.java
new file mode 100644
index 0000000000..80b048beca
--- /dev/null
+++ b/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/CoreShareTicket.java
@@ -0,0 +1,108 @@
+package io.dataease.share.dao.auto.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+
+/**
+ *
+ *
+ *
+ *
+ * @author fit2cloud
+ * @since 2024-06-21
+ */
+@TableName("core_share_ticket")
+public class CoreShareTicket implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ private Long id;
+
+ /**
+ * 分享uuid
+ */
+ private String uuid;
+
+ /**
+ * ticket
+ */
+ private String ticket;
+
+ /**
+ * ticket有效期
+ */
+ private Long exp;
+
+ /**
+ * ticket参数
+ */
+ private String args;
+
+ /**
+ * 首次访问时间
+ */
+ private Long accessTime;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getTicket() {
+ return ticket;
+ }
+
+ public void setTicket(String ticket) {
+ this.ticket = ticket;
+ }
+
+ public Long getExp() {
+ return exp;
+ }
+
+ public void setExp(Long exp) {
+ this.exp = exp;
+ }
+
+ public String getArgs() {
+ return args;
+ }
+
+ public void setArgs(String args) {
+ this.args = args;
+ }
+
+ public Long getAccessTime() {
+ return accessTime;
+ }
+
+ public void setAccessTime(Long accessTime) {
+ this.accessTime = accessTime;
+ }
+
+ @Override
+ public String toString() {
+ return "CoreShareTicket{" +
+ "id = " + id +
+ ", uuid = " + uuid +
+ ", ticket = " + ticket +
+ ", exp = " + exp +
+ ", args = " + args +
+ ", accessTime = " + accessTime +
+ "}";
+ }
+}
diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/CoreShareTicketMapper.java b/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/CoreShareTicketMapper.java
new file mode 100644
index 0000000000..cb912a7c07
--- /dev/null
+++ b/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/CoreShareTicketMapper.java
@@ -0,0 +1,18 @@
+package io.dataease.share.dao.auto.mapper;
+
+import io.dataease.share.dao.auto.entity.CoreShareTicket;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author fit2cloud
+ * @since 2024-06-21
+ */
+@Mapper
+public interface CoreShareTicketMapper extends BaseMapper {
+
+}
diff --git a/core/core-backend/src/main/java/io/dataease/share/manage/ShareTicketManage.java b/core/core-backend/src/main/java/io/dataease/share/manage/ShareTicketManage.java
new file mode 100644
index 0000000000..e639f8be70
--- /dev/null
+++ b/core/core-backend/src/main/java/io/dataease/share/manage/ShareTicketManage.java
@@ -0,0 +1,153 @@
+package io.dataease.share.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import io.dataease.api.xpack.share.request.TicketCreator;
+import io.dataease.api.xpack.share.request.TicketDelRequest;
+import io.dataease.api.xpack.share.request.TicketSwitchRequest;
+import io.dataease.api.xpack.share.vo.TicketVO;
+import io.dataease.api.xpack.share.vo.TicketValidVO;
+import io.dataease.commons.utils.CodingUtil;
+import io.dataease.exception.DEException;
+import io.dataease.share.dao.auto.entity.CoreShareTicket;
+import io.dataease.share.dao.auto.entity.XpackShare;
+import io.dataease.share.dao.auto.mapper.CoreShareTicketMapper;
+import io.dataease.share.dao.auto.mapper.XpackShareMapper;
+import io.dataease.share.dao.ext.mapper.XpackShareExtMapper;
+import io.dataease.utils.AuthUtils;
+import io.dataease.utils.BeanUtils;
+import io.dataease.utils.IDUtils;
+import jakarta.annotation.Resource;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Component
+public class ShareTicketManage {
+
+ @Resource
+ private CoreShareTicketMapper coreShareTicketMapper;
+
+ @Resource
+ private XpackShareMapper xpackShareMapper;
+
+ @Resource
+ private XpackShareExtMapper xpackShareExtMapper;
+
+ public CoreShareTicket getByTicket(String ticket) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("ticket", ticket);
+ return coreShareTicketMapper.selectOne(queryWrapper);
+ }
+
+ public String saveTicket(TicketCreator creator) {
+ String ticket = creator.getTicket();
+ if (StringUtils.isNotBlank(ticket)) {
+ CoreShareTicket ticketEntity = getByTicket(ticket);
+ if (ObjectUtils.isNotEmpty(ticketEntity)) {
+ if (creator.isGenerateNew()) {
+ ticketEntity.setAccessTime(null);
+ ticketEntity.setTicket(CodingUtil.shortUuid());
+ }
+ ticketEntity.setArgs(creator.getArgs());
+ ticketEntity.setExp(creator.getExp());
+ ticketEntity.setUuid(creator.getUuid());
+ coreShareTicketMapper.updateById(ticketEntity);
+ return ticketEntity.getTicket();
+ }
+ }
+ ticket = CodingUtil.shortUuid();
+ CoreShareTicket linkTicket = new CoreShareTicket();
+ linkTicket.setId(IDUtils.snowID());
+ linkTicket.setTicket(ticket);
+ linkTicket.setArgs(creator.getArgs());
+ linkTicket.setExp(creator.getExp());
+ linkTicket.setUuid(creator.getUuid());
+ coreShareTicketMapper.insert(linkTicket);
+ return ticket;
+ }
+
+ public void deleteTicket(TicketDelRequest request) {
+ String ticket = request.getTicket();
+ if (StringUtils.isBlank(ticket)) {
+ DEException.throwException("ticket为必填参数");
+ }
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("ticket", ticket);
+ coreShareTicketMapper.delete(queryWrapper);
+ }
+
+ public void switchRequire(TicketSwitchRequest request) {
+ String resourceId = request.getResourceId();
+ Boolean require = request.getRequire();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("resource_id", resourceId);
+ queryWrapper.eq("creator", AuthUtils.getUser().getUserId());
+ XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
+ xpackShare.setTicketRequire(require);
+ xpackShareMapper.updateById(xpackShare);
+ }
+
+ public List query(Long resourceId) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("resource_id", resourceId);
+ queryWrapper.eq("creator", AuthUtils.getUser().getUserId());
+ XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
+ if (ObjectUtils.isEmpty(xpackShare)) return null;
+ String uuid = xpackShare.getUuid();
+ if (StringUtils.isBlank(uuid)) return null;
+ QueryWrapper ticketQueryWrapper = new QueryWrapper<>();
+ ticketQueryWrapper.eq("uuid", uuid);
+ List coreShareTickets = coreShareTicketMapper.selectList(ticketQueryWrapper);
+ if (CollectionUtils.isEmpty(coreShareTickets)) return null;
+ return coreShareTickets.stream().map(item -> BeanUtils.copyBean(new TicketVO(), item)).toList();
+ }
+
+ @Transactional
+ public void updateByUuidChange(String originalUuid, String newUuid) {
+ xpackShareExtMapper.updateTicketUuid(originalUuid, newUuid);
+ }
+
+ @Transactional
+ public void deleteByShare(String uuid) {
+ QueryWrapper ticketQueryWrapper = new QueryWrapper<>();
+ ticketQueryWrapper.eq("uuid", uuid);
+ coreShareTicketMapper.delete(ticketQueryWrapper);
+ }
+
+ public TicketValidVO validateTicket(String ticket, XpackShare share) {
+ TicketValidVO vo = new TicketValidVO();
+ if (StringUtils.isBlank(ticket)) {
+ vo.setTicketValid(!share.getTicketRequire());
+ return vo;
+ }
+ CoreShareTicket linkTicket = getByTicket(ticket);
+ if (ObjectUtils.isEmpty(linkTicket)) {
+ vo.setTicketValid(false);
+ return vo;
+ }
+ vo.setTicketValid(true);
+ vo.setArgs(linkTicket.getArgs());
+ Long accessTime = linkTicket.getAccessTime();
+ long now = System.currentTimeMillis();
+ if (ObjectUtils.isEmpty(accessTime)) {
+ accessTime = now;
+ vo.setTicketExp(false);
+ linkTicket.setAccessTime(accessTime);
+ coreShareTicketMapper.updateById(linkTicket);
+ return vo;
+ }
+ Long exp = linkTicket.getExp();
+ if (ObjectUtils.isEmpty(exp) || exp.equals(0L)) {
+ vo.setTicketExp(false);
+ return vo;
+ }
+ long expTime = exp * 60L * 1000L;
+ long time = now - accessTime;
+ vo.setTicketExp(time > expTime);
+ return vo;
+ }
+}
diff --git a/core/core-backend/src/main/java/io/dataease/share/server/ShareTicketServer.java b/core/core-backend/src/main/java/io/dataease/share/server/ShareTicketServer.java
new file mode 100644
index 0000000000..f89ca4f1e3
--- /dev/null
+++ b/core/core-backend/src/main/java/io/dataease/share/server/ShareTicketServer.java
@@ -0,0 +1,40 @@
+package io.dataease.share.server;
+
+import io.dataease.api.xpack.share.ShareTicketApi;
+import io.dataease.api.xpack.share.request.TicketCreator;
+import io.dataease.api.xpack.share.request.TicketDelRequest;
+import io.dataease.api.xpack.share.request.TicketSwitchRequest;
+import io.dataease.api.xpack.share.vo.TicketVO;
+import io.dataease.share.manage.ShareTicketManage;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.List;
+
+@RestController
+@RequestMapping("/ticket")
+public class ShareTicketServer implements ShareTicketApi {
+
+ @Resource
+ private ShareTicketManage shareTicketManage;
+
+ @Override
+ public String saveTicket(TicketCreator creator) {
+ return shareTicketManage.saveTicket(creator);
+ }
+
+ @Override
+ public void deleteTicket(TicketDelRequest request) {
+ shareTicketManage.deleteTicket(request);
+ }
+
+ @Override
+ public void switchRequire(TicketSwitchRequest request) {
+ shareTicketManage.switchRequire(request);
+ }
+
+ @Override
+ public List query(Long resourceId) {
+ return shareTicketManage.query(resourceId);
+ }
+}