Получите электронную почту пользователя из API Twitter для аутентификации внешнего входа. ASP.NET MVC С#

Я проверил пару связанных вопросов, чтобы найти ответ на мой вопрос, но все безрезультатно. Этот вопрос Можем ли мы получить идентификатор электронной почты из Twitter oauth API? дошли до того, что получили поддержку Twitter, чтобы разрешить доступ к моему приложению ниже: Дополнительные разрешения Используя этот doc в качестве руководства и выделенный ответ code (немного изменив его бит)

var resource_url = "https://api.twitter.com/1.1/account/verify_credentials.json";
var postBody = "include_email=true";//
resource_url += "?" + postBody;

чтобы сгенерировать подпись и сделать запрос, чтобы получить данные пользователя из результатов твиттера в 401 Unauthorized в моем приложении MVC.

Однако, когда я использую инструмент генератора подписи twitter, чтобы сгенерировать заголовок авторизации и использовать fiddler, чтобы сделать запрос GET на https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true, Я получаю сообщение только один раз, и мне нужно восстановить ключи приложения в твиттере, чтобы получить его снова.

Есть ли документ о том, как создать действительную подпись и сделать правильный запрос на получение электронной почты пользователя Twitter через .Net TwitterAuthentication?

Ответ 1

После того, как я почти вылетел, вытащив все мои волосы из головы, я, наконец, получил его на работу. Я узнал, что базовая строка подписи немного отличается от той, которая была сгенерирована моим кодом. После небольших настроек я смог создать допустимую базовую строку подписи.

В Startup.cs я добавил access_token и access_secret в качестве претензий. Я не использовал тот, который был найден в моем приложении, потому что пользователям нужно вызвать новый, когда они пытаются войти или зарегистрироваться:

var twitterOptions = new Microsoft.Owin.Security.Twitter.TwitterAuthenticationOptions()
{
   ConsumerKey = ConfigurationManager.AppSettings["consumer_key"],
   ConsumerSecret = ConfigurationManager.AppSettings["consumer_secret"],
   Provider = new Microsoft.Owin.Security.Twitter.TwitterAuthenticationProvider
   {
      OnAuthenticated = (context) =>
      {
         context.Identity.AddClaim(new System.Security.Claims.Claim("urn:twitter:access_token", context.AccessToken));
         context.Identity.AddClaim(new System.Security.Claims.Claim("urn:twitter:access_secret", context.AccessTokenSecret));
         return Task.FromResult(0);
      }
   },
   BackchannelCertificateValidator = new Microsoft.Owin.Security.CertificateSubjectKeyIdentifierValidator(new[]
   {
      "A5EF0B11CEC04103A34A659048B21CE0572D7D47", // VeriSign Class 3 Secure Server CA - G2
      "0D445C165344C1827E1D20AB25F40163D8BE79A5", // VeriSign Class 3 Secure Server CA - G3
      "7FD365A7C2DDECBBF03009F34339FA02AF333133", // VeriSign Class 3 Public Primary Certification Authority - G5
      "39A55D933676616E73A761DFA16A7E59CDE66FAD", // Symantec Class 3 Secure Server CA - G4
      "‎add53f6680fe66e383cbac3e60922e3b4c412bed", // Symantec Class 3 EV SSL CA - G3
      "4eb6d578499b1ccf5f581ead56be3d9b6744a5e5", // VeriSign Class 3 Primary CA - G5
      "5168FF90AF0207753CCCD9656462A212B859723B", // DigiCert SHA2 High Assurance Server C‎A 
      "B13EC36903F8BF4701D498261A0802EF63642BC3" // DigiCert High Assurance EV Root CA
    }),
    CallbackPath = new PathString("/twitter/account/ExternalLoginCallback")
};

 app.UseTwitterAuthentication(twitterOptions);

И, наконец, в моем контроллере я просто вызвал мой вспомогательный класс, чтобы получить имя и адрес электронной почты из твиттера:

    if (loginInfo.Login.LoginProvider.ToLower() == "twitter")
    {
        string access_token = loginInfo.ExternalIdentity.Claims.Where(x => x.Type == "urn:twitter:access_token").Select(x => x.Value).FirstOrDefault();
        string access_secret = loginInfo.ExternalIdentity.Claims.Where(x => x.Type == "urn:twitter:access_secret").Select(x => x.Value).FirstOrDefault();
        TwitterDto response = MyHelper.TwitterLogin(access_token, access_secret, ConfigurationManager.AppSettings["consumer_key"], ConfigurationManager.AppSettings["consumer_secret"]);
       // by now response.email should possess the email value you need
    }

Метод класса помощника:

Это был раздел, который я настроил, чтобы сделать правильный запрос:

baseString = string.Concat( "GET &", Uri.EscapeDataString(resource_url) + "&" + Uri.EscapeDataString(request_query), "% 26", Uri.EscapeDataString(baseString));

public static TwitterDto TwitterLogin(string oauth_token, string oauth_token_secret, string oauth_consumer_key, string oauth_consumer_secret)
        {
            // oauth implementation details
            var oauth_version = "1.0";
            var oauth_signature_method = "HMAC-SHA1";

            // unique request details
            var oauth_nonce = Convert.ToBase64String(
                new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
            var timeSpan = DateTime.UtcNow
                - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();

            var resource_url = "https://api.twitter.com/1.1/account/verify_credentials.json";
            var request_query = "include_email=true";
            // create oauth signature
            var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
                            "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}";

            var baseString = string.Format(baseFormat,
                                        oauth_consumer_key,
                                        oauth_nonce,
                                        oauth_signature_method,
                                        oauth_timestamp,
                                        oauth_token,
                                        oauth_version
                                        );

            baseString = string.Concat("GET&", Uri.EscapeDataString(resource_url) + "&" + Uri.EscapeDataString(request_query), "%26", Uri.EscapeDataString(baseString));

            var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                                    "&", Uri.EscapeDataString(oauth_token_secret));

            string oauth_signature;
            using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey)))
            {
                oauth_signature = Convert.ToBase64String(
                    hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes(baseString)));
            }

            // create the request header
            var headerFormat = "OAuth oauth_consumer_key=\"{0}\", oauth_nonce=\"{1}\", oauth_signature=\"{2}\", oauth_signature_method=\"{3}\", oauth_timestamp=\"{4}\", oauth_token=\"{5}\", oauth_version=\"{6}\"";

            var authHeader = string.Format(headerFormat,
                                    Uri.EscapeDataString(oauth_consumer_key),
                                    Uri.EscapeDataString(oauth_nonce),
                                    Uri.EscapeDataString(oauth_signature),
                                    Uri.EscapeDataString(oauth_signature_method),
                                    Uri.EscapeDataString(oauth_timestamp),
                                    Uri.EscapeDataString(oauth_token),
                                    Uri.EscapeDataString(oauth_version)
                            );


            // make the request

            ServicePointManager.Expect100Continue = false;
            resource_url += "?include_email=true";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
            request.Headers.Add("Authorization", authHeader);
            request.Method = "GET";

            WebResponse response = request.GetResponse();
            return JsonConvert.DeserializeObject<TwitterDto>(new StreamReader(response.GetResponseStream()).ReadToEnd());
        }
    }

    public class TwitterDto
    {
        public string name { get; set; }
        public string email { get; set; }
    }

Это все, что нужно для получения электронной почты пользователя Twitter. Я надеюсь, что это поможет кому-то бороться с этим. Обратите внимание, что шаги, упомянутые в вопросе, также очень важны.

Ответ 2

вам нужно изменить свой код, чтобы вызвать метод GET/verify_credentials после входа пользователя в твиттер. И важно установить для параметра include_email значение true. Когда это значение установлено на истинное сообщение электронной почты, оно будет возвращено в пользовательских объектах в виде строки. Я использую эту библиотеку https://www.nuget.org/packages/linqtotwitter так что мне не нужно писать код для обработки запросов twitter api

var twitterCtx = new TwitterContext(authTwitter);
var verifyResponse = await
    (from acct in twitterCtx.Account
    where (acct.Type == AccountType.VerifyCredentials) && (acct.IncludeEmail == true)
    select acct)
    .SingleOrDefaultAsync();

посмотри, как я это сделал здесь http://www.bigbrainintelligence.com/Post/get-users-email-address-from-twitter-oauth-ap

это простое и чистое решение