从远程文件共享下载文件会导致拒绝访问

Kar*_*mar 6 c# asp.net sharepoint httpresponse ashx

我在ASP.Net Generic处理程序中有以下代码来下载文件.

// generate you file
// set FilePath and FileName variables
string stFile = FilePath + FileName;
try {
    response.Clear();
    response.ContentType = "application/pdf";
    response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
    response.TransmitFile(stFile);
} catch (Exception ex) {
    // any error handling mechanism
} finally {
    response.End();
}
Run Code Online (Sandbox Code Playgroud)

它适用于本地路径 - 如"D:\ Files\Sample.pdf"或"\ localserver\Files\Sample.pdf".

但它在尝试访问网络文件共享时抛出并访问被拒绝的错误,如"\ anotherServer\Files\Sample.pdf".

它与双跳有关吗?如果我可以使用spsecurity.runwithelevatedprivileges来解决此问题?或者其他选择是什么?

根据这篇文章,https://weblogs.asp.net/owscott/iis-windows-authentication-and-the-double-hop-issue似乎是一个双跳问题.我该如何解决这个问题?我想要的是最终用户应该能够使用asp.net泛型处理程序下载远程资源.

小智 4

我必须处理一次类似的事情,并通过将网络共享映射到特定驱动器来使其工作。

在尝试访问网络共享之前将凭据添加到网络共享的解决方案不起作用(但您可以尝试将其作为第一次尝试)

NetworkCredential nc = new NetworkCredential("<login>", "<pass>");
CredentialCache cache = new CredentialCache();
cache.Add(new Uri("<your network share>"), "Basic", nc);
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,请使用将网络共享映射到驱动器的组合解决方案。使用类对和NetworkDrive进行 WinApi 调用:WNetAddConnection2WNetCancelConnection2

public class NetworkDrive
{
    public enum ResourceScope
    {
        RESOURCE_CONNECTED = 1,
        RESOURCE_GLOBALNET,
        RESOURCE_REMEMBERED,
        RESOURCE_RECENT,
        RESOURCE_CONTEXT
    }

    public enum ResourceType
    {
        RESOURCETYPE_ANY,
        RESOURCETYPE_DISK,
        RESOURCETYPE_PRINT,
        RESOURCETYPE_RESERVED
    }

    public enum ResourceUsage
    {
        RESOURCEUSAGE_CONNECTABLE = 0x00000001,
        RESOURCEUSAGE_CONTAINER = 0x00000002,
        RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
        RESOURCEUSAGE_SIBLING = 0x00000008,
        RESOURCEUSAGE_ATTACHED = 0x00000010,
        RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
    }

    public enum ResourceDisplayType
    {
        RESOURCEDISPLAYTYPE_GENERIC,
        RESOURCEDISPLAYTYPE_DOMAIN,
        RESOURCEDISPLAYTYPE_SERVER,
        RESOURCEDISPLAYTYPE_SHARE,
        RESOURCEDISPLAYTYPE_FILE,
        RESOURCEDISPLAYTYPE_GROUP,
        RESOURCEDISPLAYTYPE_NETWORK,
        RESOURCEDISPLAYTYPE_ROOT,
        RESOURCEDISPLAYTYPE_SHAREADMIN,
        RESOURCEDISPLAYTYPE_DIRECTORY,
        RESOURCEDISPLAYTYPE_TREE,
        RESOURCEDISPLAYTYPE_NDSCONTAINER
    }

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public ResourceScope dwScope = 0;
        public ResourceType dwType = 0;
        public ResourceDisplayType dwDisplayType = 0;
        public ResourceUsage dwUsage = 0;
        public string lpLocalName = null;
        public string lpRemoteName = null;
        public string lpComment = null;
        public string lpProvider = null;
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NETRESOURCE lpNetResource, string lpPassword, string lpUsername, int dwFlags);

    [DllImport("mpr.dll")]
    static extern int WNetCancelConnection2(string lpName, Int32 dwFlags, bool bForce);

    private const int CONNECT_UPDATE_PROFILE = 0x1;
    private const int NO_ERROR = 0;

    public int MapNetworkDrive(string unc, string drive, string user, string password)
    {
        NETRESOURCE myNetResource = new NETRESOURCE();
        myNetResource.lpLocalName = drive;
        myNetResource.lpRemoteName = unc;
        myNetResource.lpProvider = null;
        int result = WNetAddConnection2(myNetResource, password, user, 0);
        if (result == 0)
            return result;
        else
            throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    public int UnmapNetworkDrive(string drive)
    {
        int result = WNetCancelConnection2(drive, CONNECT_UPDATE_PROFILE, true);
        if (result != NO_ERROR)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

NetworkDrive nd = new NetworkDrive();

try
{
    if (nd.MapNetworkDrive("<your network share>", "Z:", "<login>", "<pass>") == 0)
    {
        NetworkCredential nc = new NetworkCredential("<login>", "<pass>");
        CredentialCache cache = new CredentialCache();
        cache.Add(new Uri("<your network share>"), "Basic", nc);

        // access network share using UNC path (not your drive letter)
    }
}
finally
{
    nd.UnmapNetworkDrive("Z:");
}
Run Code Online (Sandbox Code Playgroud)