如何强制 Microsoft.IdentityModel.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue 使用网络代理?

How to force Microsoft.IdentityModel.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue to use web proxy?

我正在创建一个将使用 CSOM 连接到 SharePoint Online 的守护程序应用程序。我的应用程序将 运行 在互联网代理后面的公司环境中。我正在使用标准的 SharePoint 加载项模型,提供 TokenHelper 和 SharePointContext 类,使用 Microsoft.IdentityModel.Extensions.dll.

我在两个地方设置了 TokenHelper 使用代理:GetRealmFromTargetUrl 中的 WebRequest 和 AcsMetadataParser 中的 WebClient。

但它不起作用,因为在我看来 DLL 使用了另一个 Web 请求。以下是触发异常的执行的 StackTraces:

Exception Message: Token request failed.
Stack Trace:    
   at Microsoft.IdentityModel.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue(String securityTokenServiceUrl, OAuth2AccessTokenRequest oauth2Request)
   at ScriptTask_d38d98a4cb054097ac7c2ece4802bf9a.spo.TokenHelper.GetAppOnlyAccessToken(String targetPrincipalName, String targetHost, String targetRealm)
   at ScriptTask_d38d98a4cb054097ac7c2ece4802bf9a.ScriptMain.Main()

Inner Exception Message: Unable to connect to the remote server
Inner Stack Trace:    
   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
   at System.Net.HttpWebRequest.GetRequestStream()
   at Microsoft.IdentityModel.S2S.Protocols.OAuth2.OAuth2WebRequest.GetResponse()
   at Microsoft.IdentityModel.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue(String securityTokenServiceUrl, OAuth2AccessTokenRequest oauth2Request)

不知是否有解决办法?

绕过它。

而不是这个调用:

oauth2Response = 
    client.Issue(AcsMetadataParser.GetStsUrl(targetRealm), 
    oauth2Request) as OAuth2AccessTokenResponse;

我使用以下代码创建了一个静态方法 IssueToken 和一个虚拟方法 "mapping" class:

private static OAuth2AccessTokenResponse IssueToken(string sts, OAuth2AccessTokenRequest oauth2Request) {
    string requestString = "grant_type=" + System.Web.HttpUtility.UrlEncode(oauth2Request.GrantType) +
                            "&client_id=" + System.Web.HttpUtility.UrlEncode(oauth2Request.ClientId) +
                            "&client_secret=" + System.Web.HttpUtility.UrlEncode(oauth2Request.ClientSecret) +
                            "&resource=" + System.Web.HttpUtility.UrlEncode(oauth2Request.Resource);

    string tokenResponse;

    byte[] byteArray = Encoding.UTF8.GetBytes(requestString);

    WebRequest request = WebRequest.Create(sts);
    request.Proxy = new System.Net.WebProxy { Address = new Uri(InternetProxy) };
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";

    request.ContentLength = byteArray.Length;

    using (Stream reqStream = request.GetRequestStream()) {
        reqStream.Write(byteArray, 0, byteArray.Length);
    }
    using (WebResponse response = request.GetResponse()) {
        using (Stream respStream = response.GetResponseStream()) {
            using (StreamReader reader = new StreamReader(respStream)) {
                tokenResponse = reader.ReadToEnd();
            }
        }
    }

    JavaScriptSerializer jss = new JavaScriptSerializer();
    OAuth2AccessTokenResponseDummy dummy = jss.Deserialize<OAuth2AccessTokenResponseDummy>(tokenResponse);

    OAuth2AccessTokenResponse oauth2Response = new OAuth2AccessTokenResponse () {
        TokenType = dummy.token_type,
        ExpiresIn = dummy.expires_in,
        NotBefore = jss.Deserialize<DateTime>(@"""\/Date(" + dummy.not_before + @")\/""").ToLocalTime(),
        ExpiresOn = jss.Deserialize<DateTime>(@"""\/Date(" + dummy.expires_on + @")\/""").ToLocalTime(),
        Scope = dummy.resource,
        AccessToken = dummy.access_token
    };

    return oauth2Response;
}

private class OAuth2AccessTokenResponseDummy {
    public string token_type { get; set; }
    public string expires_in { get; set; }
    public string not_before { get; set; }
    public string expires_on { get; set; }
    public string resource { get; set; }
    public string access_token { get; set; }
}

而且我还在 GetClientContextWithAccessToken 的委托中添加了网络代理:

public static ClientContext GetClientContextWithAccessToken(string targetUrl, string accessToken) {
    ClientContext clientContext = new ClientContext(targetUrl);

    clientContext.AuthenticationMode = ClientAuthenticationMode.Anonymous;
    clientContext.FormDigestHandlingEnabled = false;
    clientContext.ExecutingWebRequest +=
        delegate(object oSender, WebRequestEventArgs webRequestEventArgs) {
            webRequestEventArgs.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
            webRequestEventArgs.WebRequestExecutor.WebRequest.Proxy = webProxy;
        };

    return clientContext;
}