¿Hay alguna manera de otorgar acceso mediante programación a un usuario específico a un archivo estático específico?

Ejemplo: un usuario carga /wwwroot/files/users/2137/document.pdf. Ahora bien, este archivo no debería ser accesible navegando a www.domain.com/files/users/2137/document.pdf. Solo este usuario, u otros usuarios a los que se les otorgue acceso, podrían acceder a él a través del sistema backend.

0
Stian 27 oct. 2019 a las 13:04

1 respuesta

La mejor respuesta

Puede usar un Middleware + Authorization Policy para lograr ese objetivo:

  1. Defina una política donde el usuario solo pueda acceder a sus propios recursos.
  2. Invoque IAuthorizationService dentro de un middleware que verifica la política antes de que entre en el middleware StaticFiles.

Por ejemplo, aquí hay un AuthorizationHandler que maneja este requisito:

public class RestrictStaticFilesRequirement: AuthorizationHandler<RestrictStaticFilesRequirement>,IAuthorizationRequirement 
{
    public const string DefaultPolicyName = "Access-His-Own-Static-Files";
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RestrictStaticFilesRequirement requirement)
    {
        var user = context.User;                      // current User Principal
        var userName = context.Resource as string;    // current userName
        // custom this requirement as you like
        if(user != null && !string.IsNullOrEmpty(userName) && user.HasClaim(ClaimTypes.NameIdentifier, userName)) {
            context.Succeed(requirement);
        } else {
            context.Fail();
        }
        return Task.CompletedTask;
    }
}

Registre este requisito como Policy:

services.AddAuthorization(opts =>{
    opts.AddPolicy(RestrictStaticFilesRequirement.DefaultPolicyName,pb => pb.AddRequirements(new RestrictStaticFilesRequirement()) );
});

Finalmente, verifique la política usando IAuthorizationService y determine si la solicitud actual está permitida:

app.UseAuthentication();

app.UseWhen( ctx => ctx.Request.Path.StartsWithSegments("/files/users"), appBuilder =>{
    appBuilder.Use(async (context, next) => {
        // get the userId in current Path : "/files/users/{userId}/...."
        var userId = context.Request.Path.Value.Substring("/files/users/".Length)
            .Split('/')
            .FirstOrDefault();
        if(string.IsNullOrEmpty(userId)){
            await next();    // current URL is not for static files
            return;
        }
        var auth= context.RequestServices.GetRequiredService<IAuthorizationService>();
        var result = await auth.AuthorizeAsync( context.User, userId ,RestrictStaticFilesRequirement.DefaultPolicyName);
        if(!result.Succeeded){
            context.Response.StatusCode= 403;
            return;
        }
        await next();
    });
});
app.UseStaticFiles();

// ... other middlewares
1
itminus 28 oct. 2019 a las 05:52