简体   繁体   中英

How can I restrict the access to a static file to a specific logged in user?

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.

You could use a Middleware + Authorization Policy to achieve that goal:

  1. Define a policy where the user can only access his own resources.
  2. Invoke the 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM