65.9K
CodeProject 正在变化。 阅读更多。
Home

提取 Facebook 身份验证令牌并代表用户上传照片的极其简单的方法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (2投票s)

2014年12月19日

CPOL

6分钟阅读

viewsIcon

34157

downloadIcon

512

自定义身份验证提供程序,提取 Facebook 用户身份验证令牌和一个模拟 Facebook 用户的网站示例代码。

引言

如果您曾想知道像 HootsuiteKontentKloud 这样的社交发布公司是如何保存用户 Facebook 登录数据并随后代表该用户发布消息到 Facebook 的,本文将为您解答。您还可以下载此处讨论的完整项目。

背景

Microsoft Visual Studio 的最新更新使得创建允许用户使用外部登录提供程序(如 Facebook)登录的网站变得非常容易。您所需要做的就是从 Facebook 开发者网站获取应用程序密钥。不幸的是,Microsoft 提供的默认 Facebook 身份验证提供程序不允许保存用户身份验证令牌以供以后重用。

在本文中,我将展示如何创建一个非常简单的身份验证提供程序,它能够实现这一点,允许您将 Facebook 身份验证令牌保存到数据库中,然后登录并模拟另一个用户上传图片到 Facebook。

Using the Code

以下是构建示例网站的 5 个步骤

  1. 创建默认 MVC 网站
  2. 添加自定义身份验证提供程序以提取用户令牌
  3. 在用户配置文件中添加令牌字段,用于保存令牌
  4. 自定义账户控制器,以便在注册期间实际将令牌保存到用户配置文件中
  5. 添加使用持久化令牌上传图片到 Facebook 的代码

这听起来可能很复杂,但实际上只需几行代码即可完成所有这些操作。

步骤 1

打开 Visual Studio 2013 并使用个人用户账户进行身份验证来创建默认 MVC 网站。

Default MVC website

将项目命名为 PersistentFacebookAuth

第二步

向项目添加新类,命名为 MyFacebookAuthenticationProvider.cs。将此代码添加到类中

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Security.Facebook;

namespace PersistentFacebookAuth
{
    public class MyFacebookAuthenticationProvider : FacebookAuthenticationProvider
    {
        public const string MyTokenClaimName = "my:FacebookToken";

        public override Task Authenticated(FacebookAuthenticatedContext context)
        {
            context.Identity.AddClaim(new Claim(MyTokenClaimName, context.AccessToken));
            return base.Authenticated(context);
        }
    }
}

此代码用一行代码扩展了默认的 FacebookAuthenticationProvider,它从身份验证上下文中获取 AccessToken 并将其保存在 Claims 集合中。稍后,在 Account 控制器中,我们将使用声明名称 "my:FacebookToken" 在 Claims 集合中找到该令牌。这是一个任意名称,您可以自己想一个,它必须在集合中是唯一的 - 为了方便起见,我们将其存储在 MyTokenClaimName 常量中。

我们现在准备好配置我们的网站,以利用新的身份验证提供程序进行 Facebook 登录。

App_Start 文件夹中,找到并打开 Startup.Auth.cs 文件。在代码中找到此处

//app.UseFacebookAuthentication(
//   appId: "",
//   appSecret: "");

如果您取消注释这些行,将使用默认提供程序。我们不需要那个。相反,我们将添加代码来指导应用程序使用我们的自定义提供程序

var fbOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
    SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
    AppId = "--your id here --",
    AppSecret = "-- your key here --",
    Provider = new MyFacebookAuthenticationProvider()
};

fbOptions.Scope.Add("email");
fbOptions.Scope.Add("read_stream");
fbOptions.Scope.Add("publish_stream");

app.UseFacebookAuthentication(fbOptions);

不要忘记从 Facebook 开发者网站复制 AppIdAppSecret 密钥。(有关该过程的简单描述可以在此处找到)。

您还可以更改 Scope 集合 - 它定义了您的应用程序在身份验证时将向用户请求的权限。

步骤 3

现在,我们需要一个地方来存储身份验证令牌。任何可以容纳长 strings 的地方都可以。在此示例中,我们在持有用户配置文件的 AspNetUsers 数据库表中添加了另一列。您真的不需要对该数据库了解太多。只需添加一行代码,项目中的默认后端将完成其余的工作。

Models 文件夹中,找到并打开 IdentityModels.cs 文件。将 FacebookToken 字段声明添加到 ApplicationUser 类中

public string FacebookToken { get; set; }

ApplicationUser 类现在应该像这样

public class ApplicationUser : IdentityUser
{
    public string FacebookToken { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined 
        // in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync
                (this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

在您网站首次运行时,将生成数据库并将 FacebookToken 列添加到 AspNetUsers 表中。

步骤 4

现在,我们需要修改 Account 控制器,以便在注册过程中实际将令牌保存到用户配置文件中。这发生在用户通过 Facebook 身份验证并确认注册之后。

Controllers 文件夹中,找到并打开 AccountController.cs 文件。找到 ExternalLoginConfirmation 函数

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, 
    string returnUrl)

在函数内部,找到构造新的 ApplicationUser 的行

var user = new ApplicationUser { UserName = model.Email, Email = model.Email };

在这里,我们将添加我们自定义身份验证提供程序已经提取的身份验证令牌。在 ApplicationUser 构造函数上方添加一行新代码

var tokenClaim = info.ExternalIdentity.Claims.FirstOrDefault
    (c => c.Type == MyFacebookAuthenticationProvider.MyTokenClaimName);

在这里,我们搜索 Claims 集合以找到我们自定义的持有身份验证令牌的声明。

现在,修改 ApplicationUser 构造函数以添加 FacebookToken

var user = new ApplicationUser 
    { UserName = model.Email, Email = model.Email, FacebookToken = tokenClaim.Value };

保存令牌到用户配置文件的结果代码片段应该如下所示

var tokenClaim = info.ExternalIdentity.Claims.FirstOrDefault
(c => c.Type == MyFacebookAuthenticationProvider.MyTokenClaimName);
var user = new ApplicationUser 
{ UserName = model.Email, Email = model.Email, FacebookToken = tokenClaim.Value };
var result = await UserManager.CreateAsync(user);

这完成了提取和保存 Facebook 用户身份验证令牌的部分。

下一步,我们将更改默认主页视图和控制器,以演示如何在无需用户登录的情况下,使用令牌将图片上传到用户的 Facebook 帐户。

步骤 5 - 上传示例

此步骤的目标是修改主页以显示文件上传按钮和已注册用户列表,允许您将图片上传到所选用户的 Facebook 个人资料。

为了节省您的时间,代码使用了可以从 NuGet 获取的 Facebook 库。右键单击项目名称,选择“管理 NuGet 包...”选项,然后在搜索框中输入“facebook

package

找到 Facebook 包并单击安装。您现在可以完成我们的项目了。

在 Controllers 文件夹中,找到并打开 HomeController.cs 文件。
我们这里要做的第一件事是显示当前已注册并拥有 Facebook 登录信息的用户的列表。像这样修改 Index 函数

public ActionResult Index()
{
    var users = HttpContext.GetOwinContext().GetUserManager
    <ApplicationUserManager>().Users.Where(u => u.FacebookToken != null).ToList();
    if (users != null && users.Count > 0) ViewBag.Users = users;
           
    return View();
}

在这里,我们将用户列表放入 ViewBag。现在让我们修改主页 Index 视图。在 Views/Home 文件夹中,找到并打开 Index.cshtml 文件。

在任何你喜欢的地方添加这段 HTML 代码

@if (ViewBag.Users != null)
{
    <div class="col-md-8">
        @using (Html.BeginForm("Upload", "Home", 
        FormMethod.Post, new { enctype = "multipart/form-data" }))
        {
            <div class="form-horizontal">
                <div class="form-group">
                    <label class="col-md-6 control-label">Select picture to upload:</label>
                    <div class="col-md-6">
                        <input type="file" name="file" />
                    </div>
                </div>
                <div class="form-group">
                    <label class="col-md-7 control-label">Choose Facebook account to upload
                    </label>
                </div>
                @foreach (PersistentFacebookAuth.Models.ApplicationUser user in ViewBag.Users)
                {
                    <div class="form-group">
                        <label class="col-md-6 control-label">@user.Email</label>
                        <div class="col-md-6">
                            <button class="btn btn-success" id="userID" 
                            name="userID" value="@user.Id">Upload</button>
                        </div>
                    </div>
                }
            </div>
        }
    </div>
}

这里最重要的是 HTML 表单、输入类型="file" 和列出注册用户电子邮件以及相应提交按钮的 foreach 语句。当您点击按钮时,将调用 home 控制器的 Upload 操作,并传入相应的 userID 值。

现在让我们创建这个 Upload 动作函数,它将完成所有上传工作。

再次打开 HomeController.cs 文件。在那里添加此代码

[HttpPost]
public async Task<ActionResult> Upload(string userID)
{
    if (Request.Files.Count > 0)
    {
        var selectedUser = await HttpContext.GetOwinContext().GetUserManager
        <ApplicationUserManager>().FindByIdAsync(userID);
        var facebookUserID = selectedUser.Logins.Where
        (u => u.LoginProvider == "Facebook").Select(u => u.ProviderKey).FirstOrDefault();
        var facebookUserToken = selectedUser.FacebookToken;

        var imgFile = Request.Files[0];

        if (imgFile != null && imgFile.ContentLength > 0)
        {
            var pictureBytes = new byte[imgFile.ContentLength];
            imgFile.InputStream.Read(pictureBytes, 0, imgFile.ContentLength);

            await uploadToFacebook(facebookUserID, 
            facebookUserToken, pictureBytes, Path.GetFileName(imgFile.FileName));

            return Redirect("<a abp="9652" 
            href="https://#/">https://#/" + facebookUserID);
        }
    }

    return RedirectToAction("Index");
}

首先,我们获取提供的 userID 并从配置文件数据库表中检索 selectedUser 数据。对于该用户,我们填充 facebookUserIDfacebookUserToken 变量 - 我们将在上传图片到 Facebook 时使用这些值。

之后,我们从请求中检索图片文件名和图片字节数组,并将所有数据发送到 uploadToFacebook 函数。

以下是 uploadToFacebook 函数的代码,它实际上会将图片上传到 Facebook,并模拟选定的用户。

private async Task<bool> uploadToFacebook(string facebookUserID, 
string token, byte[] pictureBytes, string fileName)
{
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

    var mediaObj = new FacebookMediaObject
    {
        FileName = fileName,
        ContentType = "image/" + Path.GetExtension(fileName).Substring(1),
    };
    mediaObj.SetValue(pictureBytes);

    var args = new Dictionary<string, object>();
    args.Add("source", mediaObj);

    var client = new FacebookClient(token);
    await client.PostTaskAsync(string.Format("/{0}/photos", facebookUserID), args);

    return true;
}

在这里的第一行,我们告诉 .NET 库使用 TLS 安全协议 - Facebook 停止响应默认的 SSL3 请求。

然后,我们将图像字节打包到 FacebookMediaObject 中,并将该对象添加到参数集合中。

现在,我们来到在 FacebookClient 构造函数中使用身份验证令牌的地方。这实际上是整个练习的重点 - 使用注册过程中保存的令牌来模拟 Facebook 用户。

最后,我们将上传请求提交给 Facebook,并将请求者重定向到用户的图像库。

就是这样。您现在拥有一个可以正常运行的网站,允许您将图片上传到其他用户的 Facebook 相册。

下载源代码以查看所有代码并尝试一下。

请记住,这是一个示例,而不是生产质量的网站。此外,您绝不应允许陌生人发布到其他用户的 Facebook 个人资料(请参阅 Facebook 网站上的许可证和其他文档)。

关注点

类似的代码可用于连接到 Twitter 或 LinkedIn。如果您想知道如何实现,请在此处留言,我将发布另一篇包含更多详细信息的文章。

您可以在此处查看此代码在实际生产系统中的工作方式:https://my.kontentkloud.com/account/register/010basic

我计划撰写另一篇文章,介绍如何将您的网站连接到 Microsoft Office 365 商业云。如果您对此主题有具体问题,请给我留言。

© . All rights reserved.