使用HttpWebRequest进行Yammer身份验证

时间:2014-08-19 17:03:59

标签: yammer

我目前正在开发一个需要使用Yammer API的项目。目的是绕过使用浏览器,并使用HttpWebRequest进行所有身份验证。最初,这对我有用,但现在我尝试调用GetResponse()时出现404错误。

对于我的网址,我尝试过使用
https://www.yammer.com/session?client_id= {CLIENT_ID}
以及
https://www.yammer.com/session

using (var stream = webrequest.GetRequestStream())
{
    stream.Write(postdata, 0, postdata.Length);
}

try
{
    webresponse = webrequest.GetResponse() as HttpWebResponse;
}
catch (WebException ex)
{
    webresponse = ex.Response as HttpWebResponse;
}

他们是否更改了网址,或者我做错了什么?

1 个答案:

答案 0 :(得分:3)

以下是我对yammer身份验证的代码段。 Steve Pescha的文章 - http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx解释了如何执行Programmatic yammer身份验证。我根据自己的需要定制了它。

public class YammerSession 
{
    #region Variables

    /// <summary>
    /// The client identifier
    /// </summary>
    private readonly string clientId = "XXXXXXXX";

    /// <summary>
    /// client secret
    /// </summary>
    private readonly string clientSecret = "XXXXXXXX";

    /// <summary>
    /// Cookie container that stores yammer authentication information
    /// </summary>
    private CookieContainer cookieContainer = new CookieContainer(2);

    /// <summary>
    /// The user code sent in response to login request
    /// </summary>
    private string userCode;

    /// <summary>
    /// The user email
    /// </summary>
    private string email;

    /// <summary>
    /// The user password
    /// </summary>
    private SecureString password;

    #endregion

    #region Methods

    /// <summary>
    /// Gets the supported yammer version
    /// </summary>
    public static int SupportedVersion
    {
        get
        {
            return 1;
        }
    }

    /// <summary>
    /// Gets the client id.
    /// </summary>
    public string ClientId
    {
        get
        {
            return this.clientId;
        }
    }

    /// <summary>
    /// Gets the authenticity token.
    /// </summary>
    /// <value>
    /// The authenticity token.
    /// </value>
    public string AuthenticityToken { get; private set; }

    /// <summary>
    /// Gets the token.
    /// </summary>
    /// <value>
    /// The token.
    /// </value>
    public string Token { get; private set; }

    /// <summary>
    /// Connects the specified connection.
    /// </summary>
    public override void Connect()
    {
        this.InternalLogin(this.Connection.User, this.Connection.Password);            
    }

    /// <summary>
    /// Disconnects this instance.
    /// </summary>
    public override void Disconnect()
    {            
        // Log out
        this.InternalLogout(this.Connection.Address);            
    }

    /// <summary>
    /// Creates the web request to a service endpoint.
    /// </summary>        
    /// <param name="serviceEndpoint">The service endpoint.</param>
    /// <returns>
    /// A new HTTP web request.
    /// </returns>
    public string GetEndpoint(string serviceEndpoint)
    {            
        // Get the uri
        var requestUri = string.Format("{0}/api/v{1}/{2}", this.Connection.Address, SupportedVersion, serviceEndpoint);

        // return the result
        return requestUri;
    }

    /// <summary>
    /// Connects the specified email.
    /// </summary>
    /// <param name="email">The email.</param>
    /// <param name="password">The password.</param>
    private void InternalLogin(string email, SecureString password)
    {            
        this.email = email;
        this.password = password;

        // Get the user code.
        this.GetUserCode();

        // Now get the bearer token
        this.GetBearerToken(this.userCode);            
    }

    /// <summary>
    /// Gets the user code.
    /// </summary>                        
    private void GetUserCode()
    {            
        string yammerAuthUrl = string.Format("https://www.yammer.com/dialog/oauth?client_id={0}", this.clientId);
        string yammerSessionUrl = string.Format("https://www.yammer.com/session?client_id={0}", this.clientId);

        // The authenticity token
        string authenticityToken = string.Empty;

        // Make a get request to Yammer authentication endpoint and get the response
        using (HttpWebResponse webResponse = this.MakeGetRequestToEndPoint(yammerAuthUrl))
        {
            // Set the cookies
            this.SetCookies(webResponse);

            // Look for authenticity token
            authenticityToken = this.GetAuthenticityToken(SessionHelper.ConvertResponseStreamToString(webResponse, Encoding.UTF8));
        }

        if (!string.IsNullOrEmpty(authenticityToken))
        {
            // Construct the post body with user login information
            string postBody = string.Format(
                        "{0}{1}{2}{3}{4}{5}{6}",
                        "utf8=%E2%9C%93&authenticity_token=",
                        HttpUtility.UrlEncode(authenticityToken),
                        "&network_permalink=&login=",
                        HttpUtility.UrlEncode(this.email),
                        "&password=",
                        HttpUtility.UrlEncode(this.password.ConvertToUnsecureString()),
                        "&remember_me=off");

            // Make the first post for User Code
            HttpWebResponse sessionPostWebResponse = this.MakePostRequestToEndPoint(postBody, yammerSessionUrl);
            string postResults = this.GetResponseAsString(sessionPostWebResponse);

            // Get the next auth token that was returned. This will be used for logout purposes
            this.AuthenticityToken = this.GetAuthenticityToken(postResults);

            using (HttpWebResponse webResponse = this.MakeGetRequestToEndPoint(yammerAuthUrl, true))
            {
                // Now look for the query string and set the user code
                this.userCode = webResponse.ResponseUri.Query;

                // Check whether we are in Authorization Page
                if (this.userCode.IndexOf("?client_id") >= 0)
                {
                    // Construct the yammer network name
                    string yammerNetworkName = webResponse.ResponseUri.AbsolutePath.Substring(0, webResponse.ResponseUri.AbsolutePath.ToLower().IndexOf("dialog/"));

                    // Construct the yammer decision url
                    string yammerUserAuthDecisionUrl = string.Format(
                                    "{0}{1}{2}{3}{4}",
                                    "https://www.yammer.com",
                                    yammerNetworkName,
                                    "oauth2/decision?client_id=",
                                    this.clientId,
                                    "&redirect_uri=https%3A%2F%2Fwww.yammer.com&response_type=code");

                    // Construct the Payload for authorization page
                    string payLoad = "utf8=%E2%9C%93&authenticity_token=" + HttpUtility.UrlEncode(this.AuthenticityToken) + "&allow=Allow";

                    // Authorize the app by posting the request 
                    using (HttpWebResponse decisionPostWebResponse = this.MakePostRequestToEndPoint(payLoad, yammerUserAuthDecisionUrl))
                    {
                        // Reset the user Code
                        this.userCode = decisionPostWebResponse.ResponseUri.Query;
                    }
                }

                // App should have been granted access at this point if it did not already have access. 
                // Now check whether the code is present in the query string
                if (this.userCode.IndexOf("?code=") < 0)
                {
                    throw new ArgumentException(Properties.ErrorMessges.UnableToLogin);
                }

                this.userCode = this.userCode.Replace("?code=", string.Empty);
            }
        }            
    }

    /// <summary>
    /// Get Yammer Authenticity Token
    /// </summary>
    /// <param name="rawHtml">The Yammer response that was got after posting to yammer endpoint</param>
    /// <returns>The Yammer authenticity token</returns>
    private string GetAuthenticityToken(string rawHtml)
    {            
        string result = string.Empty;

        int at = rawHtml.IndexOf("<meta name=\"authenticity_token\" id=\"authenticity_token\"");

        if (at > -1)
        {
            // Get the authenticity token string
            int et = rawHtml.IndexOf("/>", at + 1);
            string tokenText = rawHtml.Substring(at, et - at);

            // Get the token value
            int ts = tokenText.IndexOf("content=");
            int es = tokenText.LastIndexOf("\"");

            result = tokenText.Substring(ts + 9, es - ts - 9);
        }

        return result;
    }

    /// <summary>
    /// Perform a get request to an endpoint and return the Http response
    /// </summary>
    /// <param name="endPoint">The endpoint to make the request</param>
    /// <param name="addCookies">Should cookies be added to the request</param>
    /// <returns>The Http Web Response</returns>
    private HttpWebResponse MakeGetRequestToEndPoint(string endPoint, bool addCookies = false)
    {            
        HttpWebRequest webRequest = WebRequest.CreateHttp(endPoint);

        webRequest.Method = "GET";
        if (addCookies)
        {
            webRequest.CookieContainer = this.cookieContainer;
        }

        return (HttpWebResponse)webRequest.GetResponse();
    }

    /// <summary>
    /// Read the cookies from the web response object and store it in the cookie container instance variable
    /// </summary>
    /// <param name="webResponse">The Web Response object</param>
    private void SetCookies(HttpWebResponse webResponse)
    {            
        const string YAMTRAK_COOKIE = "yamtrak_id";
        const string SESSION_COOKIE = "_workfeed_session_id";
        const string LOGIN_CSRF_TOKEN_COOKIE = "login_csrf_token";

        string cookies = webResponse.Headers["Set-Cookie"];
        if (string.IsNullOrEmpty(cookies))
        {
            this.cookieContainer = new CookieContainer();
        }
        else
        {
            // Split the cookie based on , and ;
            string[] sepChar = new string[2];
            sepChar[0] = ",";
            sepChar[1] = ";";
            string[] cookieArray = cookies.Split(sepChar, StringSplitOptions.None);

            // Declare variables to hold the different types of cookies
            string login_csrf_token = string.Empty;
            string yammerTrakToken = string.Empty;
            string sessionToken = string.Empty;

            // Parse the cookie array and store the cookies in the array
            for (int i = 0; i < cookieArray.Length; i++)
            {
                if (cookieArray[i].IndexOf(YAMTRAK_COOKIE) >= 0)
                {
                    yammerTrakToken = cookieArray[i];
                }
                if (cookieArray[i].IndexOf(SESSION_COOKIE) >= 0)
                {
                    sessionToken = cookieArray[i];
                }
                if (cookieArray[i].IndexOf(LOGIN_CSRF_TOKEN_COOKIE) >= 0)
                {
                    login_csrf_token = cookieArray[i];
                }
            }

            // Create the cookie container
            this.cookieContainer = new CookieContainer();

            // Get the value for each of the cookie and add it to the cookie container                
            if (!string.IsNullOrWhiteSpace(yammerTrakToken))
            {
                yammerTrakToken = yammerTrakToken.Substring(YAMTRAK_COOKIE.Length + 1);
                this.cookieContainer.Add(new Cookie(YAMTRAK_COOKIE, yammerTrakToken, "/", "www.yammer.com"));
            }
            if (!string.IsNullOrWhiteSpace(sessionToken))
            {
                sessionToken = sessionToken.Substring(SESSION_COOKIE.Length + 1);
                this.cookieContainer.Add(new Cookie(SESSION_COOKIE, sessionToken, "/", "www.yammer.com"));
            }
            if (!string.IsNullOrWhiteSpace(login_csrf_token))
            {
                login_csrf_token = login_csrf_token.Substring(LOGIN_CSRF_TOKEN_COOKIE.Length + 1);
                this.cookieContainer.Add(new Cookie(LOGIN_CSRF_TOKEN_COOKIE, login_csrf_token, "/", "www.yammer.com"));
            }
        }            
    }

    /// <summary>
    /// Make a post request to an endpoint and return the result
    /// </summary>
    /// <param name="postBody">The post request payload</param>
    /// <param name="endPoint">The endpoint</param>
    /// <returns>The response got from the server</returns>
    private HttpWebResponse MakePostRequestToEndPoint(string postBody, string endPoint)
    {            
        string responseString = string.Empty;

        HttpWebRequest webRequest = WebRequest.CreateHttp(endPoint);
        webRequest.Method = "POST";
        webRequest.CookieContainer = this.cookieContainer;
        webRequest.ContentType = "application/x-www-form-urlencoded";
        SessionHelper.WritePayLoadToWebRequest(webRequest, postBody);
        HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

        return webResponse;
    }

    /// <summary>
    /// Get Response as string
    /// </summary>
    /// <param name="webResponse">The http web response object</param>
    /// <returns>The web response string</returns>
    /// <remarks>The Http Response object would be disposed after use</remarks>
    private string GetResponseAsString(HttpWebResponse webResponse)
    {            
        string responseString = string.Empty;

        using (webResponse)
        {
            responseString = SessionHelper.ConvertResponseStreamToString(webResponse, Encoding.UTF8);
        }

        return responseString;
    }

    /// <summary>
    /// Gets the user code.
    /// </summary>
    /// <param name="userCode">The user code.</param>
    /// <exception cref="System.TimeoutException">Waiting for login page load.
    /// or
    /// Waiting for post login page load.</exception>
    private void GetBearerToken(string userCode)
    {            
        string formatUri = string.Format("https://www.yammer.com/oauth2/access_token.json?client_id={0}&client_secret={1}&code={2}", this.clientId, this.clientSecret, userCode);

        Uri yammerUri = new Uri(formatUri);

        WebRequest webRequest = WebRequest.Create(yammerUri);
        webRequest.Method = "GET";

        using (WebResponse response = webRequest.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                DataContractJsonSerializer seralizer = new DataContractJsonSerializer(typeof(Model.JSON.Yammer.AccessTokenResponse));
                Model.JSON.Yammer.AccessTokenResponse accessTokenResponse = (Model.JSON.Yammer.AccessTokenResponse)seralizer.ReadObject(responseStream);

                if (string.IsNullOrWhiteSpace(accessTokenResponse.access_token.token))
                {
                    throw new InvalidOperationException("Unable to extract Yammer.com authorization bearer token.");
                }

                // Set the bearer token
                this.Token = accessTokenResponse.access_token.token;
            }
        }            
    }

    /// <summary>
    /// Internal logout.
    /// </summary>
    /// <param name="address">The address.</param>
    private void InternalLogout(string address)
    {            
        string formatUri = string.Format("{0}/logout?from=nav", address);

        Uri yammerUri = new Uri(formatUri);

        // Create request
        var request = HttpWebRequest.CreateHttp(yammerUri);

        // POST
        request.Method = "POST";

        // Set the cookie container
        request.CookieContainer = this.cookieContainer;

        // Sent the request body            
        request.ContentType = "application/x-www-form-urlencoded";
        string requestBody = string.Format(
            "authenticity_token={0}&_method=delete",
            HttpUtility.UrlEncode(this.AuthenticityToken));
        byte[] requestBodyUTF8 = Encoding.UTF8.GetBytes(requestBody);

        // Set the length before writing the request steam.
        request.ContentLength = requestBody.Length;

        // Write the request stream
        using (var requestStream = request.GetRequestStream())
        {
            using (StreamWriter streamWrite = new StreamWriter(requestStream))
            {
                streamWrite.Write(requestBody);
            }
        }

        // Make the request
        using (var response = request.GetResponse())
        {
            // Always read the response
            using (Stream responseStream = response.GetResponseStream())
            {
            }
        }
    }

    #endregion
}

在上面的代码中,替换您的客户端ID,客户端密码,电子邮件和密码。然后,您可以使用connect方法获取持有者令牌并断开连接以退出yammer。 最近yammer改变了来回传递的cookie的数量,我已经解决了这个问题