package jnpf.fileStorage;
|
|
import jnpf.base.ActionResult;
|
import jnpf.base.ActionResultCode;
|
import jnpf.exception.DataException;
|
import jnpf.file.WorkflowFileAccessApi;
|
import jnpf.model.fileaccess.WorkflowFileGrant;
|
import jnpf.model.fileaccess.WorkflowFileRequest;
|
import jnpf.util.JsonUtil;
|
import jnpf.util.TicketUtil;
|
import jnpf.util.UserProvider;
|
import lombok.Data;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import java.util.*;
|
import java.util.function.Function;
|
|
/** 流程动作准入与 Office 配置上下文绑定;文件传输使用原有公共能力。 */
|
@Service
|
public class WorkflowFileTicketService {
|
private static final String PREVIEW_CONFIG = "workflow-file-preview-config-v2";
|
private final WorkflowFileAccessApi access;
|
private final Function<String, String> reader;
|
private final Function<String, String> writer;
|
|
@Autowired public WorkflowFileTicketService(WorkflowFileAccessApi access) {
|
this(access, TicketUtil::parseTicket, payload -> TicketUtil.createTicket(payload, 300L));
|
}
|
WorkflowFileTicketService(WorkflowFileAccessApi access, Function<String, String> reader, Function<String, String> writer) {
|
this.access = access; this.reader = reader; this.writer = writer;
|
}
|
|
@Data public static class Ticket {
|
private String purpose;
|
private WorkflowFileRequest source;
|
}
|
|
public List<WorkflowFileGrant> authorizeDownloads(List<WorkflowFileRequest> requests) {
|
if (requests == null || requests.isEmpty() || requests.size() > 100) throw denied();
|
List<WorkflowFileGrant> grants = new ArrayList<>();
|
// 全部校验完成之后,调用方才可委托原单文件/打包下载。
|
for (WorkflowFileRequest request : requests) grants.add(authorizeCurrent(request, "DOWNLOAD"));
|
return grants;
|
}
|
|
public WorkflowFileGrant authorizePreview(WorkflowFileRequest request) {
|
return authorizeCurrent(request, "VIEW");
|
}
|
|
/** 仅供服务器用已验证的结果签发配置上下文,不签发新的文件读取地址。 */
|
public String previewTicket(WorkflowFileGrant grant) {
|
Ticket ticket = new Ticket(); ticket.setPurpose(PREVIEW_CONFIG); ticket.setSource(grant.getContext());
|
return writer.apply(JsonUtil.getObjectToString(ticket));
|
}
|
|
public WorkflowFileGrant previewAccess(String token) {
|
if (token == null || !token.matches("[A-Za-z0-9_-]+")) throw denied();
|
Ticket ticket;
|
try { ticket = JsonUtil.getJsonToBean(reader.apply(token), Ticket.class); }
|
catch (RuntimeException invalid) { throw denied(); }
|
if (ticket == null || !PREVIEW_CONFIG.equals(ticket.getPurpose()) || ticket.getSource() == null) throw denied();
|
WorkflowFileRequest source = ticket.getSource();
|
// 配置获取仍使用当前登录用户,不在 DS 回源请求中模拟票据属主。
|
if (!Objects.equals(UserProvider.getLoginUserId(), source.getOwnerId())
|
|| !Objects.equals(tenant(), source.getTenantId()) || !"VIEW".equals(source.getAction())) throw denied();
|
WorkflowFileGrant grant = authorize(source);
|
if (!Objects.equals(source.getRecordId(), grant.getContext().getRecordId())
|
|| !same(source.getTaskId(), grant.getContext().getTaskId())) throw denied();
|
return grant;
|
}
|
|
private WorkflowFileGrant authorizeCurrent(WorkflowFileRequest request, String action) {
|
if (request == null) throw denied();
|
String user = UserProvider.getLoginUserId();
|
if (user == null || user.isBlank()) throw denied();
|
WorkflowFileRequest copy = JsonUtil.getJsonToBean(JsonUtil.getObjectToString(request), WorkflowFileRequest.class);
|
copy.setOwnerId(user); copy.setTenantId(tenant()); copy.setAction(action);
|
return authorize(copy);
|
}
|
|
private WorkflowFileGrant authorize(WorkflowFileRequest source) {
|
ActionResult<WorkflowFileGrant> response = access.authorize(source);
|
if (response == null || !ActionResultCode.SUCCESS.getCode().equals(response.getCode()) || response.getData() == null) throw denied();
|
WorkflowFileGrant grant = response.getData();
|
WorkflowFileRequest actual = grant.getContext();
|
if (actual == null || grant.getFile() == null || !Objects.equals(source.getFileId(), grant.getFile().get("fileId"))
|
|| !Objects.equals(source.getFileId(), actual.getFileId()) || !Objects.equals(source.getTenantId(), actual.getTenantId())
|
|| !Objects.equals(source.getOwnerId(), actual.getOwnerId()) || !Objects.equals(source.getModelId(), actual.getModelId())
|
|| !Objects.equals(source.getField(), actual.getField()) || !Objects.equals(source.getAction(), actual.getAction())
|
|| !same(source.getParentField(), actual.getParentField()) || !same(source.getRowId(), actual.getRowId())
|
|| !same(source.getContentToken(), actual.getContentToken())
|
|| !same(source.getDraftId(), actual.getDraftId()) || !same(source.getLeaseId(), actual.getLeaseId())
|
|| source.getTaskId() != null && !Objects.equals(source.getTaskId(), actual.getTaskId())) throw denied();
|
return grant;
|
}
|
private static String tenant() {
|
String value = UserProvider.getUser().getTenantId();
|
return value == null || value.isBlank() ? "0" : value;
|
}
|
private static boolean same(String a, String b) { return Objects.toString(a, "").equals(Objects.toString(b, "")); }
|
private static DataException denied() { return new DataException("文件访问上下文无效、已过期或当前权限不足"); }
|
}
|