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

如何在带授权的Blazor Server应用中安全上传图片并保护API路由

如何保护API上传路由仅允许登录用户访问

我在Razor页面中使用RadzenUpload控件上传文件,代码如下:

<RadzenUpload Accept="image/*" Progress=@OnProgress class="w-100" Url=@($"/api/upload/uploadfirmlogo")/>

上传请求会发送到/api/upload/uploadfirmlogo,对应的控制器代码如下:

[ApiController]
[Microsoft.AspNetCore.Mvc.Route("api/[controller]")]
//[Authorize]
public class UploadController : Controller
{     
    private readonly IWebHostEnvironment environment;
    
    public UploadController(IWebHostEnvironment environment)
    {
        this.environment = environment;            
    }

    [HttpPost("UploadFirmLogo")]
    public async Task<IActionResult> UploadFirmLogoAsync(IFormFile[] files)
    {
        try
        {
            if (HttpContext.Request.Form.Files.Any())
            {
                var file = HttpContext.Request.Form.Files[0];
                string path = Path.Combine(environment.WebRootPath, "images", "logos", file.FileName);
                using (var stream =
                       new FileStream(path, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }
            }
            return StatusCode(200);
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
}

我的应用使用AuthenticationStateProvider处理登录流程,但不知道如何保护这个上传路由,只允许当前登录用户访问。


解决方案

1. 启用控制器/接口的认证授权

直接取消控制器上[Authorize]的注释,即可让整个UploadController的所有接口强制要求用户登录后才能访问:

[ApiController]
[Microsoft.AspNetCore.Mvc.Route("api/[controller]")]
[Authorize] // 启用授权验证
public class UploadController : Controller
{
    // 控制器原有代码不变
}

如果只想单独保护UploadFirmLogo接口,也可以把[Authorize]标注在该方法上:

[HttpPost("UploadFirmLogo")]
[Authorize] // 仅对该上传接口启用授权
public async Task<IActionResult> UploadFirmLogoAsync(IFormFile[] files)
{
    // 方法原有代码不变
}

2. 确保RadzenUpload携带认证凭证

RadzenUpload通过AJAX发送请求,需保证请求能带上当前用户的认证信息:

  • 若使用Cookie认证:ASP.NET Core默认会自动在AJAX请求中携带认证Cookie,无需额外配置。
  • 若使用JWT令牌:需要在Razor页面中获取令牌,并通过RadzenUpload的Headers属性添加认证头:
    @inject AuthenticationStateProvider AuthStateProvider
    
    @code {
        private string _authToken;
    
        protected override async Task OnInitializedAsync()
        {
            var authState = await AuthStateProvider.GetAuthenticationStateAsync();
            _authToken = authState.User.FindFirst("access_token")?.Value;
        }
    }
    
    修改RadzenUpload控件添加请求头:
    <RadzenUpload Accept="image/*" Progress=@OnProgress class="w-100" 
                 Url=@($"/api/upload/uploadfirmlogo")
                 Headers=@(new Dictionary<string, string> { {"Authorization", $"Bearer {_authToken}" } }) />
    

3. 额外安全加固措施

  • 验证文件合法性:不要仅依赖前端的Accept属性(可被篡改),在控制器内验证文件类型和大小:
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif" };
    var extension = Path.GetExtension(file.FileName).ToLower();
    if (!allowedExtensions.Contains(extension))
    {
        return BadRequest("仅允许上传图片格式文件");
    }
    
    // 限制文件大小(示例:最大10MB)
    if (file.Length > 10 * 1024 * 1024)
    {
        return BadRequest("文件大小不能超过10MB");
    }
    
  • 避免文件名冲突与安全风险:不要直接使用用户上传的文件名,生成唯一文件名存储:
    var uniqueFileName = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
    string path = Path.Combine(environment.WebRootPath, "images", "logos", uniqueFileName);
    
  • 细粒度权限控制(可选):如果需要限制特定角色用户上传,可使用[Authorize(Roles = "Admin")],或在方法内获取用户信息判断:
    var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    // 根据userId校验用户是否拥有上传权限
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:54:57