You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drupal 10内容分类标记接口请求遭遇403认证错误求助

问题描述

在Drupal 10中通过Blazor发送POST请求上传文件到文件端点可成功执行,但调用内容端点创建自定义「Sharepoint Resources」类型节点时,返回403禁止错误,提示「This authentication type is not allowed」。需要实现将上传的文件关联到该自定义内容类型,并添加标签。

错误原因分析
  1. Drupal REST认证配置限制:Drupal默认可能未允许Basic认证用于节点创建的REST请求,或者对应角色缺少创建「Sharepoint Resources」内容的权限。
  2. 请求数据不完整:现有代码未将上传得到的文件ID关联到节点的文件字段,也未使用选中的标签值。
  3. REST格式/权限配置缺失:未确保「Sharepoint Resources」内容类型的REST端点启用了JSON格式,且对应用户角色有操作权限。
修复步骤

1. 配置Drupal后台权限与REST设置

  • 启用RESTful Web Services和Serialization模块。
  • 进入/admin/config/services/rest,找到Node的REST配置,确保:
    • 允许POST方法。
    • 勾选Basic authentication作为认证方式。
    • 勾选json作为请求/响应格式。
  • 进入/admin/people/permissions,给当前认证用户(如admin)授予:
    • Create sharepoint_resources content权限。
    • Access POST on Node resource权限。
    • Create file权限(已存在,否则文件上传不会成功)。

2. 修正Blazor代码中的请求逻辑

需要完成以下修改:

  • 将上传得到的文件ID关联到自定义内容类型的文件字段(假设字段名为field_shared_file)。
  • 将选中的标签值添加到节点的标签字段(假设字段名为field_tags,且为分类术语引用字段)。
  • 确保请求头正确,避免重复设置导致的问题。
完整修正代码
@page "/upload"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.Forms
@using System.Net.Http
@using System.Net.Http.Headers
@using System.IO
@using Newtonsoft.Json.Linq
@using System.Text
@using System.Net
@using Newtonsoft.Json

<PageTitle>Upload</PageTitle>

<h3>Upload File</h3>

<label for="fileInput">Select a file to upload:</label>
<InputFile id="fileInput" OnChange="HandleFileChange" />

<label for="tag">Choose a tag:</label>
<select @bind="tag" name="tag" id="tag">
    <option value="hr">HR</option>
    <option value="connectcare">ConnectCare</option>
</select>

<button @onclick="UploadFile">Upload File</button>

<p>@uploadResult</p>

@code {
    private string uploadResult;
    private IBrowserFile selectedFile;
    private string tag;
    private List<UploadedFile> uploadedFiles = new List<UploadedFile>();

    // 自定义类用于存储上传文件信息
    public class UploadedFile
    {
        public string FileName { get; set; }
        public string FileId { get; set; }
    }

    private async Task HandleFileChange(InputFileChangeEventArgs e)
    {
        selectedFile = e.File;
    }

    private async Task<byte[]> ReadFileAsync(IBrowserFile file)
    {
        using (var memoryStream = new MemoryStream())
        {
            await file.OpenReadStream().CopyToAsync(memoryStream);
            return memoryStream.ToArray();
        }
    }

    private async Task UploadFile()
    {
        if (selectedFile == null || string.IsNullOrEmpty(tag))
        {
            uploadResult = "请选择文件和标签";
            return;
        }

        var handler = new HttpClientHandler()
        {
            CookieContainer = new CookieContainer(),
            UseCookies = true,
            UseDefaultCredentials = false
        };

        using (var httpClient = new HttpClient(handler))
        {
            httpClient.BaseAddress = new Uri("http://localhost/drupal10/web/");

            // 设置Basic认证头
            var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes("admin:Testingdrupal"));
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
            // 提前设置Accept头,避免重复添加
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // 1. 上传文件到Drupal对应内容类型的文件字段端点
            var fileBytes = await ReadFileAsync(selectedFile);
            var fileContent = new ByteArrayContent(fileBytes);
            fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = $"\"{selectedFile.Name}\""
            };

            var fileUploadResponse = await httpClient.PostAsync("file/upload/node/sharepoint_resources/field_shared_file", fileContent);
            if (!fileUploadResponse.IsSuccessStatusCode)
            {
                uploadResult = $"文件上传失败: {await fileUploadResponse.Content.ReadAsStringAsync()}";
                return;
            }

            var fileUploadResponseContent = await fileUploadResponse.Content.ReadAsStringAsync();
            var fileJsonResponse = JObject.Parse(fileUploadResponseContent);
            var fileId = fileJsonResponse["fid"][0]["value"].ToString();

            // 2. 创建Sharepoint Resources节点,关联文件和标签
            var nodeData = new
            {
                type = new { target_id = "sharepoint_resources" },
                title = new { value = selectedFile.Name }, // 使用文件名作为标题更合理
                field_shared_file = new[]
                {
                    new { target_id = fileId }
                },
                field_tags = new[]
                {
                    new { target_id = tag } // 若标签是术语ID,替换为对应数值
                }
            };

            var nodeContent = new StringContent(JsonConvert.SerializeObject(nodeData), Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("node?_format=json", nodeContent);

            if (response.IsSuccessStatusCode)
            {
                uploadResult = $"内容创建成功,文件ID: {fileId},标签: {tag}";
                uploadedFiles.Add(new UploadedFile { FileName = selectedFile.Name, FileId = fileId });
            }
            else
            {
                uploadResult = $"创建内容失败: {response.StatusCode},响应内容: {await response.Content.ReadAsStringAsync()}";
            }
        }
    }
}
关键说明
  • 文件上传端点路径修改为file/upload/node/sharepoint_resources/field_shared_file,确保对应自定义内容类型的文件字段,而非默认的article类型字段。
  • 节点数据中添加了field_shared_file字段关联上传的文件ID,field_shared_file字段关联选中的标签值(需根据实际字段名调整)。
  • 增加了输入校验,确保文件和标签都已选择。
  • 统一设置Accept头,避免重复添加导致的潜在问题。

内容的提问来源于stack exchange,提问作者er280652

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:27:04