そのURLは、そのファイルを表示する権限を得るために、何らかの方法でコントローラーまたはhttpmoduleまたはthingIdontknowを通過する必要があります。これらの権限は日々変化する可能性があるため、ファイルの権限を頻繁にチェックする必要があります。
知らないものには名前があります。これは、承認アクション フィルターと呼ばれます。
まず、これらのファイルを提供するためのカスタム ルートを登録したとします。
routes.MapRoute(
"MyImagesRoute",
"files/{id}/{name}",
new { controller = "Files", action = "Index" }
// TODO: you could constrain the id parameter to be a GUID.
// Just Google for a Regex that will match a GUID pattern and put here
// as route constraint
);
そしてもちろん、それらに対応する対応するコントローラー:
public class FilesController: Controller
{
public ActionResult Index(Guid guid, string name)
{
var path = @"C:\files";
var file = Path.Combine(path, guid.ToString(), name);
file = Path.GetFullPath(file);
if (!file.StartsWith(path))
{
// someone tried to be smart and send
// files/{Guid}/..\..\creditcard.pdf as parameter
throw new HttpException(403, "Forbidden");
}
// TODO: adjust the mime type based on the extension
return File(file, "image/png");
}
}
残念ながら、この段階では、ユーザー ALPHA がユーザー BETA のファイルを要求することを妨げるものは何もありませんよね? それがあなたが扱いたいシナリオですよね?
それでは、このコントローラー アクションを保護するために、カスタムの Authorize 属性を書きましょう。
public class MyAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authenticated or doesn't have
// permissions to access this controller action
return false;
}
// at this stage we know that there's some user authenticated
// Let's get the Guid now from our route:
var routeData = httpContext.Request.RequestContext.RouteData;
var id = routeData.Values["id"] as string;
Guid guid;
if (!Guid.TryParse(id, out guid))
{
// invalid Guid => no need to continue any further, just deny access
return false;
}
// Now we've got the GUID that this user is requesting
// Let's see who this user is:
string username = httpContext.User.Identity.Name;
// and finally ensure that this user
// is actually the owner of the folder
return IsAuthorized(username, guid);
}
private bool IsAuthorized(string username, Guid guid)
{
// You know what to do here: hit your data store to verify
// that the currently authenticated username is actually
// the owner of this GUID
throw new NotImplementedException();
}
}
次に、コントローラー アクションをこの認証属性で装飾しましょう。
public class FilesController: Controller
{
[MyAuthorize]
public ActionResult Index(Guid guid, string name)
{
// at this stage we know that the currently authenticated user
// is authorized to access the file.
var path = @"C:\files";
var file = Path.Combine(path, guid.ToString(), name);
file = Path.GetFullPath(file);
if (!file.StartsWith(path))
{
// someone tried to be smart and send
// files/{Guid}/..\..\creditcard.pdf as parameter
throw new HttpException(403, "Forbidden");
}
var file = Path.Combine(@"c:\files", guid.ToString(), name);
// TODO: adjust the mime type based on the extension
return File(file, "image/png");
}
}