Reputation: 1602
Is there a way to programmatically grant a specific user access to a specific static file?
Example: A user uploads /wwwroot/files/users/2137/document.pdf
. Now this file should not be accessible by browsing to www.domain.com/files/users/2137/document.pdf
. Only this user, or other users which are granted access, could access it via the backend system.
Upvotes: 0
Views: 672
Reputation: 25350
You could use a Middleware
+ Authorization Policy
to achieve that goal:
IAuthorizationService
within a middleware that checks the policy before it goes into the StaticFiles
middleware.For example, here's a AuthorizationHandler
that handles this requirement:
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;
}
}
Register this requirement as a Policy
:
services.AddAuthorization(opts =>{
opts.AddPolicy(RestrictStaticFilesRequirement.DefaultPolicyName,pb => pb.AddRequirements(new RestrictStaticFilesRequirement()) );
});
Finally, check the policy using the IAuthorizationService
and determine whether current request is allowed:
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
Upvotes: 1