【问题标题】:How to authenticate to Office 365 portal via C#如何通过 C# 对 Office 365 门户进行身份验证
【发布时间】:2014-02-06 00:19:59
【问题描述】:

我有一个 Microsoft 的 Exchange 租户 (company.onmicrosoft.com)、一个管理员帐户 (admin@company.onmicrosoft.com) 以及我管理我的管理页面 (settings)。

最近,我接手了一个项目,通过 C# 自动解析来自管理页面的一些 Web 数据。我阅读了很多与 SharePoint 相关的文章,并阅读了有关 STS、SRF 文件和主动/被动联合服务的文章。

那么,让我们开始吧:

我从 https://login.microsoftonline.com/login.srf 开始,但 Fiddler 意识到我可以直接跳到 https://login.microsoftonline.com/ppsecure/post.srf 并获得相同的结果。

所以,我转到login,输入我的凭据,然后它会将管理页面转发给我。够简单吧?

因此,我决定复制网络流量并依赖以下帖子和示例:

所有这些网站都有关于屏幕抓取身份验证、ADFS 和许多其他有用信息的出色 C# 示例。问题是所有这些都是针对 SharePoint 的。

所以,我混合并匹配了代码并想出了以下内容:

static void Main3()
{
    CookieContainer cookies = new CookieContainer();
    //using Bungie example from http://stackoverflow.com/questions/2508656/logging-into-a-site-that-uses-live-com-authentication
    //Uri url = new Uri("https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=11&ct=1268167141&rver=5.5.4177.0&wp=LBI&wreply=http:%2F%2Fwww.bungie.net%2FDefault.aspx&id=42917");

    Uri url = new Uri("https://portal.microsoftonline.com/");
    HttpWebRequest http = (HttpWebRequest)HttpWebRequest.Create(url);

    http.Timeout = 30000;
    http.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0";
    http.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    http.AllowAutoRedirect = false;
    http.Headers.Add("Accept-Language", "en-us,en;q=0.5");
    http.Headers.Add("Accept-Encoding", "gzip, deflate");  //this option creates the two cookies but loads garbage HTML.  Removing this option allows the HTML to load normally
    http.KeepAlive = true;
    http.CookieContainer = new CookieContainer();
    http.Method = WebRequestMethods.Http.Get;

    HttpWebResponse response = (HttpWebResponse)http.GetResponse();

    //gets the cookies (they are set in the eighth header)
    string[] strCookies = response.Headers.GetValues(8);
    response.Close();


    Cookie manualCookie;
    string sManualCookiesString = "MSPRequ|lt=1389810702&id=271346&co=1;MSPOK|$uuid-02eeaf29-b8a5-441f-a6a6-319ed926d8bc$uuid-7f106156-1398-405f-83e5-61f177c7be25$uuid-3d2f189d-8f79-4216-97cf-23c5c22ff8ad$uuid-b93c9354-5802-4c82-ac7d-7838d2f7bdbc$uuid-071c3106-1c97-4e1e-930c-36f33b6f0b93; MSPShared|1; MSPSoftVis|@:@; MSPBack|1389810501";


    //Manually insert the cookies since the request only returns two cookies and we need six cookies
    foreach (string sCookieAndValue in sManualCookiesString.Split(';'))
    {
        string sCookieName = sCookieAndValue.Split('|')[0].Trim();
        string sCookieValue = sCookieAndValue.Split('|')[1].Trim();
        manualCookie = new Cookie(sCookieName, "\"" + sCookieValue + "\"");

        Uri manualURL = new Uri("http://login.microsoftonline.com");
        http.CookieContainer.Add(manualURL, manualCookie);
    }

    /*      //Removed because the above request only returns MSPRequ and MSPOK cookies but leaves out the others.  It's obviously broken :(
                string name, value;
                for (int i = 0; i < strCookies.Length; i++)
                {
                    name = strCookies[i].Substring(0, strCookies[i].IndexOf("="));
                    value = strCookies[i].Substring(strCookies[i].IndexOf("=") + 1, strCookies[i].IndexOf(";") - strCookies[i].IndexOf("=") - 1);
                    manualCookie = new Cookie(name, "\"" + value + "\"");

                    Uri manualURL = new Uri("http://login.microsoftonline.com");
                    //http.CookieContainer.Add(manualURL, manualCookie);
                }
     */

    //stores the cookies to be used later
    cookies = http.CookieContainer;

    http = (HttpWebRequest)HttpWebRequest.Create(url);
    response = (HttpWebResponse)http.GetResponse();
    StreamReader readStream = new StreamReader(response.GetResponseStream());
    string HTML = readStream.ReadToEnd();
    readStream.Close();

    //Get the PPSX value: these values are a bit strange and could indicate progress since I've seen a few of the following:
    //      P, Pa, Pas, Pass, Passp, Passpo, Passport, PassportRN
    //  As you can see it adds one letter at a time which could indicate where in the login process it is, but I don't know
    string PPSX = HTML.Remove(0, HTML.IndexOf("PPSX"));
    PPSX = PPSX.Remove(0, PPSX.IndexOf("value") + 7);
    PPSX = PPSX.Substring(0, PPSX.IndexOf("\""));
    //PPSX = "PassP"; //debug

    //Get this random PPFT value
    string PPFT = HTML.Remove(0, HTML.IndexOf("PPFT"));
    PPFT = PPFT.Remove(0, PPFT.IndexOf("value") + 7);
    PPFT = PPFT.Substring(0, PPFT.IndexOf("\""));

    //Get the random URL you POST to
    //string POSTURL = HTML.Remove(0, HTML.IndexOf("https://login.microsoftonline.com/ppsecure/post.srf?wa=wsignin1.0&rpsnv=2&ct="));
    //POSTURL = POSTURL.Substring(0, POSTURL.IndexOf("\""));
    //debug:
    //based on Fiddler, this page is the next page that's loaded
    string POSTURL = "https://login.microsoftonline.com/GetUserRealm.srf?login=admin%company.onmicrosoft.com&handler=1&extended=1 ";

    //POST with cookies
    HttpWebRequest http2 = (HttpWebRequest)HttpWebRequest.Create(POSTURL);

    //http.AllowAutoRedirect = false;
    http2.Accept = "application/json, text/javascript, */*; q=0.01";
    http2.Headers.Add("Accept-Encoding", "gzip, deflate");
    http2.Headers.Add("Accept-Language", "en-us,en;q=0.5");
    http2.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0";

    //http.ContentLength = 0;
    http2.KeepAlive = true;
    http.CookieContainer = cookies;
    http2.Referer = "https://login.microsoftonline.com/ppsecure/post.srf";
    http2.Method = WebRequestMethods.Http.Post;

    Stream ostream = http2.GetRequestStream();

    //used to convert strings into bytes
    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

    //Post information found via Fiddler. Values have been altered for anonymity
    byte[] buffer = encoding.GetBytes(
                                                                        "login=" + sUsername
                                                                        + "&passwd=" + sPassword
                                                                        + "&PPSX=" + PPSX
                                                                        + "&PPFT=" + PPFT
                                                                        + "&n1=107313"
                                                                        + "&n2=-1389941230500"
                                                                        + "&n3=-1389941230500"
                                                                        + "&n4=112373"
                                                                        + "&n5=112373"
                                                                        + "&n6=112373"
                                                                        + "&n7=112373"
                                                                        + "&n8=NaN"
                                                                        + "&n9=112373"
                                                                        + "&n10=112360"
                                                                        + "&n11=112358"
                                                                        + "&n12=112323"
                                                                        + "&n13=112324"
                                                                        + "&n14=112396"
                                                                        + "&n15=26"
                                                                        + "&n16=11239"
                                                                        + "&n17=112369"
                                                                        + "&n18=112315"
                                                                        + "&n19=880.9711230112345"
                                                                        + "&n20=1"
                                                                        + "&n21=1"
                                                                        + "&n22=1381236981084.398"
                                                                        + "&n23=1"
                                                                        + "&n24=46.789501123103664"
                                                                        + "&n25=0"
                                                                        + "&n26=0"
                                                                        + "&n27=0"
                                                                        + "&n28=0"
                                                                        + "&n29=-1318912363023"
                                                                        + "&n30=-1318912363023"
                                                                        + "&n31=false"
                                                                        + "&n32=false"
                                                                        + "&type=11"
                                                                        + "&LoginOptions=3" //this is 2 sometimes
                                                                        + "&NewUser=1"
                                                                        + "&idsbho=1"
                                                                        + "&PwdPad="
                                                                        + "&sso="
                                                                        + "&vv="
                                                                        + "&uiver=1"
                                                                        + "&i12=1"
                                                                        + "&i13=Firefox"
                                                                        + "&i14=26.0"
                                                                        + "&i15=1480"
                                                                        + "&i16=964"
                                                                        );
    ostream.Write(buffer, 0, buffer.Length);
    ostream.Close();

    HttpWebResponse response2 = (HttpWebResponse)http.GetResponse();
    readStream = new StreamReader(response2.GetResponseStream());
    HTML = readStream.ReadToEnd();

    response2.Close();
    ostream.Dispose();
    foreach (Cookie cookie in response2.Cookies) //this returns no cookies
    {
        Console.WriteLine(cookie.Name + ": ");
        Console.WriteLine(cookie.Value);
        Console.WriteLine(cookie.Expires);
        Console.WriteLine();
    }

    POSTURL = "https://login.microsoftonline.com/ppsecure/post.srf?bk=1389198967";
    //POST with cookies
    http = (HttpWebRequest)HttpWebRequest.Create(POSTURL);

    http.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0";
    http.AllowAutoRedirect = false;
    http.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    http.Headers.Add("Accept-Language", "en-us,en;q=0.5");
    http.KeepAlive = true;
    http.CookieContainer = cookies;
    http.Referer = "https://login.microsoftonline.com/ppsecure/post.srf";
    http.Method = WebRequestMethods.Http.Post;

    ostream = http.GetRequestStream();

    //used to convert strings into bytes
    encoding = new System.Text.ASCIIEncoding();

    //Post information
    ostream.Write(buffer, 0, buffer.Length);
    ostream.Close();

    HttpWebResponse response3 = (HttpWebResponse)http.GetResponse();
    readStream = new StreamReader(response3.GetResponseStream());
    HTML = readStream.ReadToEnd();

    response3.Close();
    ostream.Dispose();
    foreach (Cookie cookie in response3.Cookies)  //sadly this returns no cookies when it should have 18 cookies in addition to a bunch of BOX.CacheKey cookies
    {
        Console.WriteLine(cookie.Name + ": ");
        Console.WriteLine(cookie.Value);
        Console.WriteLine(cookie.Expires);
        Console.WriteLine();
    }
}

是否有人足够了解该网站的运作方式,可以就我的失败之处提供一些指导?该网站还使用 JavaScript 创建 cookie(您可以访问第一页并输入一个随机地址,您会看到一些点在用户名字段中从左到右移动。

也许我采取了错误的方法,但我们将不胜感激。如果需要,我可以提供 Fiddler 摘要会话日志。

谢谢!

附:很抱歉所有 .com 替换了实际期间字符,但我没有足够的声望点。只需搜索 [dot]com 并替换为 .com 即可撤消。

【问题讨论】:

    标签: c# office365 federated-identity


    【解决方案1】:

    在表单上放置一个WebBrowser 控件并使用它的方法和事件来控制它——它将为您处理所有重定向/cookies/等。

    如果需要,您可以隐藏它,这样用户甚至不会知道您正在使用网络浏览器...

    【讨论】:

      【解决方案2】:

      您想登录 Office 365 门户,而不是 SharePoint 管理员门户,因此有关如何登录 SharePoint 的文章对您的情况没有帮助。

      我进行了搜索,我认为要登录 Office 365 门户,首先需要 Microsoft Online Services Sign-In Assistant

      微软提供了一些关于如何管理 office365 用户的示例:

      1. Office 365: Office 365 Dashboard
      2. Office 365: Manage licenses and subscriptions for Office 365

      这两个例子都是基于微软在线服务登录助手和powershell cmdlet,所以在C#中,我们可以使用这个组件中的函数来登录。但似乎关于这个组件的文档并不多。所以如果你可以使用Powershell,你可以按照例子来做。如果你不能,你可能需要深入研究登录命令,看看如何在 C# 中实现它。

      【讨论】:

      • 马特,感谢您的帮助。 Exchange 门户是我正在使用的许多 PowerShell cmdlet 的前端,例如移动邮箱、获取统计信息等您需要关注详细信息需要身份验证。正是这部分,我不确定如何设置正确的标头、cookie 等。我遵循第一个示例,但是在查看代码时,没有提到 RSS。知道如何处理 JavaScript cookie/身份验证吗?再次感谢您。
      • 对不起,我也不知道
      • @Matt : 如何使用 c#HttpWebRequest http = (HttpWebRequest)HttpWebRequest.Create(url) 登录到 o365 中的 SharePoint 网站
      【解决方案3】:

      您需要在机器中安装 Office 365 模块进行通信。

      Powershell 命令

      $UserCredential = Get-Credential
      
      Import-PSSession $Session
      Import-Module ActiveDirectory
      Import-Module MsOnline
      
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
      
      Import-PSSession $Session
      Import-Module ActiveDirectory
      Import-Module MsOnline
      Get-Module
      

      然后你可以做任何事情 创建用户和邮箱、电子邮件别名等。 您可能必须在 C# 代码中引用 power shell 才能使其在自定义网站或 Windows 应用程序中工作

      这将连接到 Office 365:
      http://technet.microsoft.com/en-us/library/jj984289(v=exchg.150).aspx

      【讨论】:

      • 提问者希望使用 C# 代码,而不是 powershell。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2019-08-02
      相关资源
      最近更新 更多