【问题标题】:Yammer Authentication with HttpWebRequest使用 HttpWebRequest 进行 Yammer 身份验证
【发布时间】:2014-08-19 17:03:59
【问题描述】:

我目前正在处理一个需要使用 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;
}

他们更改了网址还是我做错了什么?

【问题讨论】:

    标签: yammer


    【解决方案1】:

    以下是我用于 yammer 身份验证的代码 sn-p。 Steve Pescha 的文章 - http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx 解释了如何执行程序化 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 的数量,我已经解决了这个问题

    【讨论】:

    • 谢谢,我没有注意到 cookie 的变化。一旦我更改了我的代码以包含第三个 cookie,其他一切就都到位了。
    • 您知道进行程序化 yammer 身份验证是否有任何缺点吗?如果您的系统处于生产状态并且 Yammer 更改了身份验证实施,您是否有任何恢复计划?
    • 随着最近对身份验证的更改,有没有人让它工作?
    • @Joe 我刚刚在 user3634665 的示例代码的帮助下获得了程序化 Yammer 身份验证。我必须修复几个部分(最大的部分是反序列化)但它仍然很好:)
    • @GuyPassy 最近有什么变化吗?身份验证不再使用此代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多