2013-06-18 3 views
0

Как я могу получить электронное письмо от учетной записи Microsoft? Я делаю следующее:Получение электронной почты от аутентификации oauth (Microsoft)

public ActionResult ExternalLoginCallback(string returnUrl) 
    { 
    AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl })); 
//... 

string email = null; 
       if (result.Provider.ToLower() == "google") 
       { 
        email = result.ExtraData["email"]; 
       } 
       else if (result.Provider.ToLower() == "facebook") 
       { 
        email = result.ExtraData["username"]; 
       } 
       else if (result.Provider.ToLower() == "microsoft") 
       { 
        email = result.ExtraData["????"]; 
       }  
} 

Для Google и Facebook я могу получить электронную почту, но я не могу с Microsoft? Что я должен использовать?

+0

Вы можете добавить код для расчёта лишних данных и попробовать сами? Но вы не можете гарантировать, что пользователь предоставит вам разрешение на вход в систему, чтобы поделиться своим адресом электронной почты с вами. – Rup

ответ

4

Решение:

public class MicrosoftScopedClient : IAuthenticationClient 
    { 
     private string clientId; 
     private string clientSecret; 
     private string scope; 

     private const string baseUrl = "https://login.live.com/oauth20_authorize.srf"; 
     private const string tokenUrl = "https://login.live.com/oauth20_token.srf"; 

     public MicrosoftScopedClient(string clientId, string clientSecret, string scope) 
     { 
      this.clientId = clientId; 
      this.clientSecret = clientSecret; 
      this.scope = scope; 
     } 

     public string ProviderName 
     { 
      get { return "Microsoft"; } 
     } 

     public void RequestAuthentication(HttpContextBase context, Uri returnUrl) 
     { 
      string url = baseUrl + "?client_id=" + clientId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" + HttpUtility.UrlEncode(scope) + "&response_type=code"; 
      context.Response.Redirect(url); 
     } 

     public AuthenticationResult VerifyAuthentication(HttpContextBase context) 
     { 
      string code = context.Request.QueryString["code"]; 

      string rawUrl = context.Request.Url.ToString(); 
      //From this we need to remove code portion 
      rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", ""); 

      IDictionary<string, string> userData = GetUserData(code, rawUrl); 

      if (userData == null) 
       return new AuthenticationResult(false, ProviderName, null, null, null); 

      string id = userData["id"]; 
      string username = userData["email"]; 
      userData.Remove("id"); 
      userData.Remove("email"); 

      AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData); 
      return result; 
     } 

     private IDictionary<string, string> GetUserData(string accessCode, string redirectURI) 
     { 
      string token = QueryAccessToken(redirectURI, accessCode); 
      if (token == null || token == "") 
      { 
       return null; 
      } 
      var userData = GetUserData(token); 
      return userData; 
     } 

     private IDictionary<string, string> GetUserData(string accessToken) 
     { 
      ExtendedMicrosoftClientUserData graph; 
      var request = 
       WebRequest.Create(
        "https://apis.live.net/v5.0/me?access_token=" + EscapeUriDataStringRfc3986(accessToken)); 
      using (var response = request.GetResponse()) 
      { 
       using (var responseStream = response.GetResponseStream()) 
       { 
        using (StreamReader sr = new StreamReader(responseStream)) 
        { 
         string data = sr.ReadToEnd(); 
         graph = JsonConvert.DeserializeObject<ExtendedMicrosoftClientUserData>(data); 
        } 
       } 
      } 

      var userData = new Dictionary<string, string>(); 
      userData.Add("id", graph.Id); 
      userData.Add("username", graph.Name); 
      userData.Add("name", graph.Name); 
      userData.Add("link", graph.Link == null ? null : graph.Link.AbsoluteUri); 
      userData.Add("gender", graph.Gender); 
      userData.Add("firstname", graph.FirstName); 
      userData.Add("lastname", graph.LastName); 
      userData.Add("email", graph.Emails.Preferred); 
      return userData; 
     } 

     private string QueryAccessToken(string returnUrl, string authorizationCode) 
     { 
      var entity = 
       CreateQueryString(
        new Dictionary<string, string> { 
         { "client_id", this.clientId }, 
         { "redirect_uri", returnUrl }, 
         { "client_secret", this.clientSecret}, 
         { "code", authorizationCode }, 
         { "grant_type", "authorization_code" }, 
        }); 

      WebRequest tokenRequest = WebRequest.Create(tokenUrl); 
      tokenRequest.ContentType = "application/x-www-form-urlencoded"; 
      tokenRequest.ContentLength = entity.Length; 
      tokenRequest.Method = "POST"; 

      using (Stream requestStream = tokenRequest.GetRequestStream()) 
      { 
       var writer = new StreamWriter(requestStream); 
       writer.Write(entity); 
       writer.Flush(); 
      } 

      HttpWebResponse tokenResponse = (HttpWebResponse)tokenRequest.GetResponse(); 
      if (tokenResponse.StatusCode == HttpStatusCode.OK) 
      { 
       using (Stream responseStream = tokenResponse.GetResponseStream()) 
       { 
        using (StreamReader sr = new StreamReader(responseStream)) 
        { 
         string data = sr.ReadToEnd(); 
         var tokenData = JsonConvert.DeserializeObject<OAuth2AccessTokenData>(data); 
         if (tokenData != null) 
         { 
          return tokenData.AccessToken; 
         } 
        } 
       } 
      } 

      return null; 
     } 

     private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" }; 
     private static string EscapeUriDataStringRfc3986(string value) 
     { 
      StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value)); 

      // Upgrade the escaping to RFC 3986, if necessary. 
      for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) 
      { 
       escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0])); 
      } 

      // Return the fully-RFC3986-escaped string. 
      return escaped.ToString(); 
     } 

     private static string CreateQueryString(IEnumerable<KeyValuePair<string, string>> args) 
     { 
      if (!args.Any()) 
      { 
       return string.Empty; 
      } 
      StringBuilder sb = new StringBuilder(args.Count() * 10); 

      foreach (var p in args) 
      { 
       sb.Append(EscapeUriDataStringRfc3986(p.Key)); 
       sb.Append('='); 
       sb.Append(EscapeUriDataStringRfc3986(p.Value)); 
       sb.Append('&'); 
      } 
      sb.Length--; // remove trailing & 

      return sb.ToString(); 
     } 

     protected class ExtendedMicrosoftClientUserData 
     { 
      public string FirstName { get; set; } 
      public string Gender { get; set; } 
      public string Id { get; set; } 
      public string LastName { get; set; } 
      public Uri Link { get; set; } 
      public string Name { get; set; } 
      public Emails Emails { get; set; } 
     } 

     protected class Emails 
     { 
      public string Preferred { get; set; } 
      public string Account { get; set; } 
      public string Personal { get; set; } 
      public string Business { get; set; } 
     } 
    } 

AuthConfig.cs

public static class AuthConfig 
    { 
     public static void RegisterAuth() 
     { 

      Dictionary<string, object> MicrosoftsocialData = new Dictionary<string, object>(); 
      MicrosoftsocialData.Add("Icon", "../Content/icons/microsoft.png"); 

      OAuthWebSecurity.RegisterClient(new MicrosoftScopedClient("XXXXXXXX", "YYYYYYYYYYYYY", 
       "wl.basic wl.emails"), "Microsoft", MicrosoftsocialData); 

      //...... 
     } 
    } 

Использование:

public ActionResult ExternalLoginCallback(string returnUrl) 
    { 
    AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl })); 
//... 

string email = null; 
       if (result.Provider.ToLower() == "google") 
       { 
        email = result.ExtraData["email"]; 
       } 
       else if (result.Provider.ToLower() == "facebook") 
       { 
        email = result.ExtraData["username"]; 
       } 
       else if (result.Provider.ToLower() == "microsoft") 
       { 
        email = result.UserName; 
       }  
} 

основе: How OAuthWebSecurity to obtain emails for different oauth clients, but Microsoft Client doesn’t return email, it didn’t include scope “wl.emails”

+1

Я пробовал использовать предоставленный вами код, но при получении результата я получаю Удаленный сервер возвратил ошибку: (400) Ошибка запроса Ошибка бомбардировки на HttpWebResponse tokenResponse = (HttpWebResponse) tokenRequest.GetResponse(); есть идеи? – Jay

+0

+1 Теперь это работает нормально, и я получаю адрес электронной почты, но теперь 'firstname' и' lastname' выходят как пустые. –

4

или еще проще: https://stackoverflow.com/a/22723713/1586498

var mo = 
      new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationOptions 
      { 
       CallbackPath = new Microsoft.Owin.PathString("/Callbacks/External"),//register at oAuth provider 
       ClientId = "<<yourclientid>>", 
       ClientSecret = "<<yourclientsecret>>", 
       Provider = new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationProvider 
       { 
        OnAuthenticated = (context) => 
         { 
          context.Identity.AddClaim(new Claim(providerKey, context.Identity.AuthenticationType)); 
          context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name))); 
          return System.Threading.Tasks.Task.FromResult(0); 
         } 
       } 
      }; 
mo.Scope.Add("wl.basic"); 
mo.Scope.Add("wl.emails"); //HERE IS THE GOLD 

app.UseMicrosoftAccountAuthentication(mo); 

и мой способ захвата их: ответ

var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); 
externalIdentity.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.Email)); 
0

усилителя действительно помогли мне.

Также хочу отметить, что при регистрации приложения необходимо установить флажок «Живая поддержка SDK» (https://apps.dev.microsoft.com/). В противном случае служба OAuth жалуется, что у вас нет секретности клиента (даже если вы это делаете).

Просто хотел бы добавить, как сделать это без использования вещи AuthConfig.cs в случае, если кто заинтересован (немного более ручной, но это делает его легче понять, если вы не знакомы со структурой):

public ActionResult LoginWithMicrosoftAccount(CancellationToken cancellationToken) 
{ 
    var client = new MicrosoftScopedClient(appID, appsecret, "wl.basic wl.emails"); 
    var urlNoQueryString = Request.Url.GetLeftPart(UriPartial.Path); 

    AuthenticationResult result = null; 
    if(Request.QueryString["error"]!= null) 
    {//Microsoft service returns error 
     return View(); 
    } 
    if (Request.QueryString["code"] != null) 
    { 
     result = client.VerifyAuthentication(this.HttpContext); 

     //at this point, you should get the username from result.UserName 
    } 
    if(Request.QueryString["code"]==null || result.UserName == null) 
    {//will do the redirection 
     client.RequestAuthentication(this.HttpContext, new Uri(urlNoQueryString)); 
    } 
    return View(); 
} 
Смежные вопросы