gpt4 book ai didi

javascript - 使用 Blazor Webassembly 和 ASP.NET Core 安全文件下载

转载 作者:行者123 更新时间:2023-12-03 23:04:31 25 4
gpt4 key购买 nike

我设法在这里找到了一个解决方案,展示了如何使用 JS 注入(inject)创建 Controller 和下载文件:
How can one generate and save a file client side using Blazor?
但是,将 [Authorize] 属性添加到 Controller 会阻止任何下载文件的尝试(即使已登录)。我希望授权的人只能访问下载文件。
该网站的其余部分使用 JWT 没有问题。
我的问题是如何将 JWT 身份验证添加到此文件下载功能?还是有替代方法?这些文件在服务器的文件系统中,上面的方法对内存非常友好,所以我更喜欢远离 blob。
注意:我使用的是应用内用户帐户。

最佳答案

为了保护文件下载,我使用下载请求 URI 中发送的一次性 token :

  • 定义一个类来存储一次 token

  • public class OneTimeToken
    {
    public string Id { get; set; }

    public string ClientId { get; set; }

    public string UserId { get; set; }

    public string Data { get; set; }
    }
    我更喜欢将 token 存储在数据库中,但您可以选择将其存储在内存中,但显然是服务器端。
  • 下载前创建 token

  • 在这里,我使用调用 API 的服务来创建我的 token
    public class OneTimeTokenService
    {
    private readonly IAdminStore<OneTimeToken> _store; // this my service calling the API
    private readonly AuthenticationStateProvider _stateProvider;
    private readonly IAccessTokenProvider _provider;
    private readonly IOptions<RemoteAuthenticationOptions<OidcProviderOptions>> _options;

    public OneTimeTokenService(IAdminStore<OneTimeToken> store,
    AuthenticationStateProvider state,
    IAccessTokenProvider provider,
    IOptions<RemoteAuthenticationOptions<OidcProviderOptions>> options)
    {
    _store = store ?? throw new ArgumentNullException(nameof(store));
    _stateProvider = state ?? throw new ArgumentNullException(nameof(state));
    _provider = provider ?? throw new ArgumentNullException(nameof(provider));
    _options = options ?? throw new ArgumentNullException(nameof(options));
    }

    public async Task<string> GetOneTimeToken()
    {
    // gets the user access token
    var tokenResult = await _provider.RequestAccessToken().ConfigureAwait(false);
    tokenResult.TryGetToken(out AccessToken token);
    // gets the authentication state
    var state = await _stateProvider.GetAuthenticationStateAsync().ConfigureAwait(false);
    // creates a one time token
    var oneTimeToken = await _store.CreateAsync(new OneTimeToken
    {
    ClientId = _options.Value.ProviderOptions.ClientId,
    UserId = state.User.Claims.First(c => c.Type == "sub").Value,
    Expiration = DateTime.UtcNow.AddMinutes(1),
    Data = token.Value
    }).ConfigureAwait(false);

    return oneTimeToken.Id;
    }
    }
  • 当用户点击下载链接时创建下载uri

  • 这里我使用了一个按钮,但它适用于任何 html 元素,您可以使用链接代替。
    @inject OneTimeTokenService _service
    <button class="btn btn-secondary" @onclick="Download" >
    <span class="oi oi-arrow-circle-top"></span><span class="sr-only">Download
    </span>
    </button>
    @code {
    private async Task Download()
    {
    var token = await _service.GetOneTimeToken().ConfigureAwait(false);
    var url = $"http://locahost/stuff?otk={token}";
    await _jsRuntime.InvokeVoidAsync("open", url, "_blank").ConfigureAwait(false);
    }
    }
  • 从 URL
  • 检索 token

    4.1。添加包 IdentityServer4.AccessTokenValidation到您的 API 项目。
    在 Startup ConfigureServices 方法中使用 IdentityServer 身份验证:
    services.AddTransient<OneTimeTokenService>()
    .AddAuthentication()
    .AddIdentityServerAuthentication(options =>
    {
    options.TokenRetriever = request =>
    {
    var oneTimeToken = TokenRetrieval.FromQueryString("otk")(request);
    if (!string.IsNullOrEmpty(oneTimeToken))
    {
    return request.HttpContext
    .RequestServices
    .GetRequiredService<OneTimeTokenService>()
    .GetOneTimeToken(oneTimeToken);
    }
    return TokenRetrieval.FromAuthorizationHeader()(request);
    };
    });
  • 定义一项服务以从 URI
  • 读取和使用一次性 token

    token 不能重复使用,因此在每次请求时都将其删除。
    这里只是一个示例。如果将 token 存储在 DB 中,则可以使用 EF 上下文,如果它在内存中,则可以使用对象缓存为例。
    public class OneTimeTokenService{
    private readonly IAdminStore<OneTimeToken> _store;

    public OneTimeTokenService(IAdminStore<OneTimeToken> store)
    {
    _store = store ?? throw new ArgumentNullException(nameof(store));
    }

    public string GetOneTimeToken(string id)
    {
    // gets the token.
    var token = _store.GetAsync(id, new GetRequest()).GetAwaiter().GetResult();
    if (token == null)
    {
    return null;
    }
    // deletes the token to not reuse it.
    _store.DeleteAsync(id).GetAwaiter().GetResult();
    return token.Data;
    }
    }

    关于javascript - 使用 Blazor Webassembly 和 ASP.NET Core 安全文件下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63435686/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com