31

Tôi đang phát triển một trang web trong ASP.NET MVC 5 (sử dụng phiên bản RC1 hiện tại). Trang web sẽ sử dụng Facebook để xác thực người dùng và để truy xuất dữ liệu hồ sơ ban đầu.Làm thế nào để truy cập thông tin cá nhân Facebook bằng cách sử dụng ASP.NET Identity (OWIN)?

Đối với hệ thống xác thực, tôi đang sử dụng công cụ ASP.NET Identity dựa trên OWIN mới (http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc-5.aspx), vì nó đơn giản hóa quá trình xác thực với các nhà cung cấp bên ngoài.

Vấn đề là khi người dùng đăng nhập lần đầu tiên, tôi muốn nhận địa chỉ email từ hồ sơ Facebook, nhưng dữ liệu này không được bao gồm trong các xác nhận quyền sở hữu đã tạo. Vì vậy, tôi đã nghĩ về những lựa chọn thay thế để có được địa chỉ:

  1. Hướng dẫn các cơ ASP.NET nhận dạng để bao gồm các địa chỉ email trong tập các dữ liệu được lấy từ Facebook và sau đó chuyển đổi để khiếu nại. Tôi không biết liệu điều này có thể xảy ra hay không.

  2. Sử dụng đồ thị API Facebook (https://developers.facebook.com/docs/getting-started/graphapi) để lấy địa chỉ email bằng cách sử dụng id người dùng Facebook (được bao gồm trong các dữ liệu yêu cầu). Nhưng điều này sẽ không hoạt động nếu người dùng có đặt địa chỉ email của anh ấy là riêng tư.

  3. Sử dụng API biểu đồ Facebook, nhưng chỉ định "tôi" thay vì id người dùng Facebook (https://developers.facebook.com/docs/reference/api/user). Nhưng cần có mã thông báo truy cập và tôi không biết cách (hoặc nếu nó là có thể) lấy mã thông báo truy cập mà ASP.NET sử dụng để lấy dữ liệu người dùng.

Vì vậy, câu hỏi là:

  1. Làm thế nào tôi có thể hướng dẫn các cơ ASP.NET nhận dạng để lấy thêm thông tin từ Facebook và bao gồm nó trong những tuyên bố dữ liệu?

  2. Hoặc cách khác, làm cách nào tôi có thể truy xuất mã thông báo truy cập đã tạo để mà tôi có thể tự hỏi bản thân Facebook?

Cảm ơn bạn!

Lưu ý: đối với hệ thống xác thực ứng dụng của tôi sử dụng mã dựa trên dự án mẫu được liên kết trong này SO trả lời: https://stackoverflow.com/a/18423474/4574

Trả lời

24

Để lấy thêm thông tin từ facebook bạn có thể xác định phạm vi mà bạn muốn bao gồm khi bạn cấu hình facebook tùy chọn xác thực. Lấy thông tin bổ sung đó là lấy ra có thể đạt được bằng cách thực hiện phương pháp OnAuthenticated của nhà cung cấp như thế này:

var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions() 
{ 
    Provider = new FacebookAuthenticationProvider() 
    { 
     OnAuthenticated = (context) => 
      { 
       // All data from facebook in this object. 
       var rawUserObjectFromFacebookAsJson = context.User; 

       // Only some of the basic details from facebook 
       // like id, username, email etc are added as claims. 
       // But you can retrieve any other details from this 
       // raw Json object from facebook and add it as claims here. 
       // Subsequently adding a claim here will also send this claim 
       // as part of the cookie set on the browser so you can retrieve 
       // on every successive request. 
       context.Identity.AddClaim(...); 

       return Task.FromResult(0); 
      } 
    } 
}; 

//Way to specify additional scopes 
facebookOptions.Scope.Add("..."); 

app.UseFacebookAuthentication(facebookOptions); 

mỗi mã here tôi thấy các email đã được lấy ra và thêm vào như là một tuyên bố đây nếu facebook đã gửi. Bạn không thể nhìn thấy nó?

+3

Cảm ơn bạn! Bí quyết là gọi 'facebookOptions.Scope.Add (" email ")', sau đó khi bạn nói dữ liệu email được tự động thêm làm xác nhận quyền sở hữu mà không phải phân tích cú pháp dữ liệu json. Tuy nhiên bây giờ tôi có một vấn đề mới: khi sử dụng mã của bạn, hãy gọi 'AuthenticationManager.GetExternalIdentity' trong hàm gọi lại sẽ trả về null thay vì một thể hiện của' ClaimsIdentity'. Bạn có ý tưởng về những gì có thể xảy ra không? (và có, tôi đang thêm id ứng dụng thích hợp và bí mật cho đối tượng facebookOptions) – Konamiman

+1

Ok, tìm thấy giải pháp điều tra từ đây: http://forums.asp.net/p/1927914/5516103.aspx?p=True&t= 635154678323993438. Sau đây phải thêm vào khởi tạo đối tượng facebookOptions: 'SignInAsAuthenticationType =" External "'. Tôi sẽ chấp nhận câu trả lời của bạn nhưng có thể bạn muốn chỉnh sửa câu trả lời để nó bao gồm các thủ thuật này. :-) – Konamiman

+1

Bạn có thể vui lòng chia sẻ mã mẫu để cho biết cách bạn truy xuất thông tin bổ sung (nói Ngày sinh) bên trong nhiệm vụ actionresult gọi lại không? – Santosh

2

Dưới đây là một số bước giúp bạn. Tôi đang trong quá trình viết một bài đăng trên blog nhưng sẽ mất một lúc ... - Thêm Scopes trong nhà cung cấp Fb và thêm dữ liệu trả về từ FB như tuyên bố

app.UseFacebookAuthentication(new FacebookAuthenticationOptions() 
     { 
      AppId = "", 
      AppSecret = "", 
      //Scope = "email,user_about_me,user_hometown,friends_about_me,friends_photos", 
      Provider = new FacebookAuthenticationProvider() 
      { 
       OnAuthenticated = async context => 
       { 
        foreach (var x in context.User) 
        { 
         context.Identity.AddClaim(new System.Security.Claims.Claim(x.Key, x.Value.ToString())); 
        } 
        //Get the access token from FB and store it in the database and use FacebookC# SDK to get more information about the user 
        context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken)); 
       } 
      }, 
      SignInAsAuthenticationType = "External", 
     });   
  • Sử dụng access token và gọi Facebook C# SDK để có được danh sách bạn bè cho người sử dụng

    var claimsIdentity = HttpContext.User.Identity as ClaimsIdentity; 
        var access_token = claimsIdentity.FindAll("FacebookAccessToken").First().Value; 
        var fb = new FacebookClient(access_token); 
        dynamic myInfo = fb.Get("/me/friends"); 
        var friendsList = new List<FacebookViewModel>(); 
        foreach (dynamic friend in myInfo.data) 
        { 
         friendsList.Add(new FacebookViewModel() { Name = friend.name, ImageURL = @"https://graph.facebook.com/" + friend.id + "/picture?type=large" }); 
         //Response.Write("Name: " + friend.name + "<br/>Facebook id: " + friend.id + "<br/><br/>"); 
        } 
    
+0

tôi đã theo dõi mẫu của bạn, nhưng claimIdentity = HttpContext.User.Identity như ClaimsIdentity chỉ chứa xác nhận quyền sở hữu LOCAL chứ không phải địa chỉ facebook. : ~/ –

+0

Bạn có thể thử HttpContext.Current.GetOwinContext(). Authentication.User? – Praburaj

+0

Tuyệt vời như vậy làm thế nào để bạn nhận được email người dùng từ đăng nhập bên ngoài MS Live với phạm vi, "wl.basic" và "wl.emails"? – subsci

29

Tạo đối tượng Microsoft.Owin.Security.Facebook.AuthenticationOptions mới trong Startup.ConfigureAuth (StartupAuth.cs), chuyển nó lên FacebookAppId, FacebookAppSecret và một AuthenticationProvider mới. Bạn sẽ sử dụng một biểu thức lambda để truyền phương thức OnAuthenticated một số mã để thêm các xác nhận quyền sở hữu vào danh tính chứa các giá trị mà bạn trích xuất từ ​​ngữ cảnh.Identity. Điều này sẽ bao gồm access_token theo mặc định. Bạn phải thêm email vào Phạm vi. Các thuộc tính người dùng khác có sẵn từ context.User (xem liên kết ở dưới cùng chẳng hạn).

StartUp.Auth.cs

// Facebook : Create New App 
// https://dev.twitter.com/apps 
if (ConfigurationManager.AppSettings.Get("FacebookAppId").Length > 0) 
{ 
    var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions() 
    { 
     AppId = ConfigurationManager.AppSettings.Get("FacebookAppId"), 
     AppSecret = ConfigurationManager.AppSettings.Get("FacebookAppSecret"), 
     Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider() 
     { 
      OnAuthenticated = (context) => 
       { 
        context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook")); 
        context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email, XmlSchemaString, "Facebook")); 
        return Task.FromResult(0); 
       } 
     } 

    }; 
    facebookOptions.Scope.Add("email"); 
    app.UseFacebookAuthentication(facebookOptions); 
} 

Trong AccountController, tôi trích xuất các ClaimsIdentity từ AuthenticationManager sử dụng cookie bên ngoài. Sau đó tôi thêm nó vào danh tính được tạo bằng cookie ứng dụng. Tôi đã bỏ qua bất kỳ khiếu nại nào bắt đầu bằng "... schemas.xmlsoap.org/ws/2005/05/identity/claims" vì nó dường như phá vỡ thông tin đăng nhập.

AccountController.cs

private async Task SignInAsync(CustomUser user, bool isPersistent) 
{ 
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); 
    var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); 

// Extracted the part that has been changed in SignInAsync for clarity. 
    await SetExternalProperties(identity); 

    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); 
} 

private async Task SetExternalProperties(ClaimsIdentity identity) 
{ 
    // get external claims captured in Startup.ConfigureAuth 
    ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); 

    if (ext != null) 
    { 
     var ignoreClaim = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims"; 
     // add external claims to identity 
     foreach (var c in ext.Claims) 
     { 
      if (!c.Type.StartsWith(ignoreClaim)) 
       if (!identity.HasClaim(c.Type, c.Value)) 
        identity.AddClaim(c); 
     } 
    } 
} 

Và cuối cùng, tôi muốn hiển thị bất cứ điều gì giá trị không phải là từ quyền địa phương. Tôi đã tạo một chế độ xem một phần _ExternalUserPropertiesListPartial xuất hiện trên /Account/Manage page. Tôi nhận được các xác nhận quyền sở hữu trước đây được lưu trữ từ AuthenticationManager.User.Claims và sau đó chuyển nó đến chế độ xem.

AccountController.cs

[ChildActionOnly] 
public ActionResult ExternalUserPropertiesList() 
{ 
    var extList = GetExternalProperties(); 
    return (ActionResult)PartialView("_ExternalUserPropertiesListPartial", extList); 
} 

private List<ExtPropertyViewModel> GetExternalProperties() 
{ 
    var claimlist = from claims in AuthenticationManager.User.Claims 
        where claims.Issuer != "LOCAL AUTHORITY" 
        select new ExtPropertyViewModel 
        { 
         Issuer = claims.Issuer, 
         Type = claims.Type, 
         Value = claims.Value 
        }; 

    return claimlist.ToList<ExtPropertyViewModel>(); 
} 

Và chỉ để được thấu đáo, quan điểm:

_ExternalUserPropertiesListPartial.cshtml

@model IEnumerable<MySample.Models.ExtPropertyViewModel> 

@if (Model != null) 
{ 
    <legend>External User Properties</legend> 
    <table class="table"> 
     <tbody> 
      @foreach (var claim in Model) 
      { 
       <tr> 
        <td>@claim.Issuer</td> 
        <td>@claim.Type</td> 
        <td>@claim.Value</td> 
       </tr> 
      } 
     </tbody> 
    </table> 
} 

Ví dụ làm việc và mã hoàn chỉnh là trên GitHub: https://github.com/johndpalm/IdentityUserPropertiesSample

Và mọi phản hồi, chính xác ion, hoặc cải tiến sẽ được đánh giá cao.

+0

Khi tôi thử điều này và thêm tuyên bố 'accesstoken', cuộc gọi tiếp theo đến phương thức User.Identity.GetUserId() trả về null. Chỉ cần thêm 1 xác nhận quyền sở hữu dường như phá vỡ đối tượng User.Identity ... – creatiive

21

Nó làm việc cho tôi với chỉ này trong Startup.Auth:

var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()  { 
    AppId = "*", 
    AppSecret = "**" 
}; 
facebookOptions.Scope.Add("email"); 
app.UseFacebookAuthentication(facebookOptions); 

Và sau đó trong phương pháp ExternalLoginCallback hoặc ExternalLoginConfirmation bạn nhận được email với:

ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); 
var email = ext.Claims.First(x => x.Type.Contains("emailaddress")).Value; 
+3

bạn có thể sử dụng điều này cho đoạn mã thứ hai: var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); chuỗi email = loginInfo.Email; –

4

Bạn cần phải tạo một thể hiện của FacebookAuthenticationOptions và cấu hình Provider. Provider chứa sự kiện được gọi là OnAuthenticated được kích hoạt khi bạn đăng nhập.

var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions 
{ 
    Provider = new FacebookAuthenticationProvider() 
    { 
     OnAuthenticated = (context) => 
     { 
      context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook")); 

      return Task.FromResult(0); 
     } 
    }, 

    // You can store these on AppSettings 
    AppId = ConfigurationManager.AppSettings["facebook:AppId"], 
    AppSecret = ConfigurationManager.AppSettings["facebook:AppSecret"] 
}; 

app.UseFacebookAuthentication(facebookOptions); 

Trong đoạn mã trên tôi truy cập vào các access_token bởi context.AccessToken và thêm nó vào Claims của người sử dụng loggedin hiện hành.

Để truy cập giá trị này sau đó bạn cần phải làm điều này:

var owinContext = HttpContext.GetOwinContext(); 
var authentication = owinContext.Authentication; 
var user = autentication.User; 
var claim = (user.Identity as ClaimsIdentity).FindFirst("urn:facebook:access_token"); 

string accessToken; 
if (claim != null) 
    accessToken = claim.Value; 

Để đơn giản hóa tất cả điều này, bạn có thể tạo một BaseController và làm cho tất cả Controllers kế thừa từ nó.

BaseController sẽ là:

public class BaseController : Controller 
{ 
    public IOwinContext CurrentOwinContext 
    { 
     get 
     { 
      return HttpContext.GetOwinContext(); 
     } 
    } 

    public IAuthenticationManager Authentication 
    { 
     get 
     { 
      return CurrentOwinContext.Authentication; 
     } 
    } 

    public new ClaimsPrincipal User 
    { 
     get 
     { 
      return Authentication.User; 
     } 
    } 

    public ClaimsIdentity Identity 
    { 
     get 
     { 
      return Authentication.User.Identity as ClaimsIdentity; 
     } 
    } 

    public string FacebookAccessToken 
    { 
     get 
     { 
      var claim = Identity.FindFirst("urn:facebook:access_token"); 

      if (claim == null) 
       return null; 

      return claim.Value; 
     } 
    } 
} 

Sau đó, để có mã thông báo truy cập trên mã của bạn, bạn chỉ cần truy cập vào bất động sản FacebookAccessToken.

string accessToken = FacebookAccessToken; 

Có thể lấy một số giá trị khác như

context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:username", 
    context.User.Value<string>("username"), ClaimValueTypes.String, "Facebook")); 

context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:name", 
    context.User.Value<string>("name"), ClaimValueTypes.String, "Facebook")); 

Lưu ý rằng không phải tất cả các lĩnh vực sẽ có sẵn, để có được những email mà bạn cần phải yêu cầu email Scope.

facebookOptions.Scope.Add("email"); 

Sau đó truy cập vào sự kiện OnAuthenticated như

context.User.Value<string>("email"); 
0

vài cent của tôi cho tất cả các câu trả lời ... nếu bạn vẫn muốn hỏi Facebook chính mình, nó làm cho tinh thần để có một cái nhìn vào đã tồn tại Facebook gói. Nó cung cấp một số chức năng tuyệt vời đã được triển khai, vì vậy bạn không phải tự mình thực hiện lại nó ... một số ví dụ về cách sử dụng nó bên trong ứng dụng ASP.NET MVC bạn có thể tìm thấy here.

Các vấn đề liên quan