If users don't have access to the file, they don't have access to the file, no matter what.
So, if you display real links to the file, as far as SharePoint is concerned, they cannot get the files content; when they click the link, they get an "access denied" message.
Your only option here is to build an applicative (_layouts) page; that page would take the file URL/Id+ListId/what-so-ever as a parameter.
The links to the files you inject from your Web part would be replaced by links to that _layouts page, including the file-identification parameter.
In that page, you would:
- Manually check if the incoming user is allowed to download the file, as per your business rules.
- Open an elevated section (
- Get the file content
Inject the file content into the output stream
// TODO: check if user is allowed to get the file content, as per business rules (since we're by-passing SP permissions)
using (SPSite elevatedSite = new SPSite(Request.Url.ToString()))
using (SPWeb elevatedWeb = elevatedSite.OpenWeb())
// TODO: Get the SPDocumentLibrary (myDocLib) object + file Id (fileId)
SPListItem item = myDocLib.GetItemById(fileId);
SPFile file = item.File;
// Open the file content
using (Stream fileStream = file.OpenBinaryStream())
// Prepare to send the file to the output
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + file.Name + "\""); // TODO: escape the file name, if needed
// Send the file by chunks
int bytesToRead = 4092;
byte buffer = new Byte[bytesToRead];
length = fileStream.Read(buffer, 0, bytesToRead);
Response.OutputStream.Write(buffer, 0, length);
buffer = new Byte[bytesToRead];
length = -1;
} while (length > 0);