Asp.net mvc 如何使用ASP.NET身份(OWIN)访问Facebook私人信息?

Asp.net mvc 如何使用ASP.NET身份(OWIN)访问Facebook私人信息?,asp.net-mvc,facebook-graph-api,asp.net-mvc-5,owin,asp.net-identity,Asp.net Mvc,Facebook Graph Api,Asp.net Mvc 5,Owin,Asp.net Identity,我正在用ASP.NETMVC5开发一个网站(目前使用的是RC1版本)。该网站将使用Facebook进行用户身份验证和检索初始配置文件数据 对于身份验证系统,我使用新的基于OWIN的ASP.NET Identity engine(),因为它大大简化了与外部提供者进行身份验证的过程 问题是,一旦用户首次登录,我想从Facebook个人资料中获取其电子邮件地址,但生成的声明中不包括这些数据。因此,我考虑了这些备选方案以获得地址: 指示ASP.NET标识引擎将电子邮件地址包含在 从Facebook检索并

我正在用ASP.NETMVC5开发一个网站(目前使用的是RC1版本)。该网站将使用Facebook进行用户身份验证和检索初始配置文件数据

对于身份验证系统,我使用新的基于OWIN的ASP.NET Identity engine(),因为它大大简化了与外部提供者进行身份验证的过程

问题是,一旦用户首次登录,我想从Facebook个人资料中获取其电子邮件地址,但生成的声明中不包括这些数据。因此,我考虑了这些备选方案以获得地址:

  • 指示ASP.NET标识引擎将电子邮件地址包含在 从Facebook检索并转换的数据集 索赔。我不知道这是否可能

  • 使用Facebook图形API ()至 使用Facebook用户id(即 包括在索赔数据中)。但是,如果用户已经 将他的电子邮件地址设置为私人

  • 使用Facebook图形API,但指定“我”而不是 Facebook用户id (). 但是 访问令牌是必需的,我不知道如何访问(或者是否需要) (完全可能)检索ASP.NET用于 获取用户数据

  • 因此,问题是:

  • 如何指示ASP.NET标识引擎检索 来自Facebook的其他信息,并将其包含在索赔中 数据

  • 或者,我如何检索生成的访问令牌 我可以自己问Facebook吗

  • 谢谢大家!


    注意:对于身份验证系统,我的应用程序使用基于此SO答案中链接的示例项目的代码:

    要从facebook检索其他信息,可以指定配置facebook身份验证选项时要包含的范围。通过实现提供程序的OnAuthenticated方法,可以获取检索到的其他信息,如下所示:

    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);
    

    根据我看到的代码,如果facebook发送了电子邮件,则该电子邮件已被检索并添加为声明。你看不见吗

    以下是一些对您有帮助的步骤。我正在写一篇博文,但这需要一段时间。。。 -在Fb provider中添加作用域,并将Fb返回的数据添加为声明

    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",
            });         
    
    • 使用访问令牌并致电Facebook C#SDK获取用户的好友列表

          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/>");
          }
      
      var claimsIdentity=HttpContext.User.Identity作为claimsIdentity;
      var access_token=claimsIdentity.FindAll(“FacebookAccessToken”).First().Value;
      var fb=新的FacebookClient(访问令牌);
      动态myInfo=fb.Get(“/me/friends”);
      var friendsList=新列表();
      foreach(myInfo.data中的动态好友)
      {
      添加(新的FacebookViewModel(){Name=friend.Name,ImageURL=@)https://graph.facebook.com/“+friend.id+”/picture?type=large“});
      //回复。写下(“姓名:“+friend.Name+”
      Facebook id:“+friend.id+”

      ); }

    在Startup.ConfigureAuth(StartupAuth.cs)中创建一个新的Microsoft.Owin.Security.Facebook.AuthenticationOptions对象,并将FacebookAppId、FacebookAppSecret和新的AuthenticationProvider传递给它。您将使用lambda表达式向OnAuthenticated方法传递一些代码,以向包含从context.identity提取的值的标识添加声明。默认情况下,这将包括访问\u令牌。您必须将电子邮件添加到范围中。其他用户属性可从context.user获得(例如,参见底部的链接)

    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);
    }
    
    在AccountController中,我使用外部cookie从AuthenticationManager提取ClaimSideEntity。然后,我将其添加到使用应用程序cookie创建的标识中。我忽略了任何以“…schemas.xmlsoap.org/ws/2005/05/identity/claims”开头的声明,因为它似乎破坏了登录

    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);
            } 
        }
    }
    
    [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>();
    }
    
    最后,我想显示不是来自地方当局的任何值。我创建了一个局部视图_ExternalUserPropertiesListPartial,它显示在上。我从AuthenticationManager.User.claims获取以前存储的声明,然后将其传递给视图

    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);
            } 
        }
    }
    
    [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>();
    }
    
    [ChildActionOnly]
    公共操作结果ExternalUserPropertiesList()
    {
    var extList=GetExternalProperties();
    返回(ActionResult)PartialView(“\u ExternalUserPropertiesListPartial”,extList);
    }
    私有列表GetExternalProperties()
    {
    var claimlist=来自AuthenticationManager.User.claims中的声明
    何处索赔。发卡机构!=“地方当局”
    选择新的ExtPropertyViewModel
    {
    发行人=索赔。发行人,
    类型=索赔。类型,
    价值=索赔。价值
    };
    返回claimlist.ToList();
    }
    
    更详细地说,以下观点:

    _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>
    }
    
    @model IEnumerable
    @如果(型号!=null)
    {
    外部用户属性
    @foreach(模型中的var索赔)
    {
    @索赔人
    @索赔.类型
    @索赔价值
    }
    }
    
    GitHub上提供了工作示例和完整代码:


    如有任何反馈、更正或改进,我们将不胜感激。

    Startup.Auth中,这对我来说非常有效:

    var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()        {
        AppId = "*",
        AppSecret = "**"
    };
    facebookOptions.Scope.Add("email");
    app.UseFacebookAuthentication(facebookOptions);
    
    然后在方法
    ExternalLoginCallback
    externalloginconconfirmation
    中,您将收到以下电子邮件:

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

    您需要创建一个
    FacebookAuthenticationOptions
    的实例,并配置
    提供程序
    Provider
    包含一个名为
    OnAuthenticated
    的事件,该事件在您登录时触发

    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);
    
    在上述代码中
    string accessToken = FacebookAccessToken;
    
    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"));
    
    facebookOptions.Scope.Add("email");
    
    context.User.Value<string>("email");