如何从OAuthWebSecurity获取ExtraData?

时间:2012-10-01 20:05:28

标签: oauth security

(MVC 4)

定义中的AuthConfig.cs;

OAuthWebSecurity.RegisterFacebookClient(
  appId: "21703538509...",
  appSecret: "28cbbc965e8ff6c9dc57cac9e323..."
);

ExternalLoginCallback函数,OAuthWebSecurity.VerifyAuthentication返回的结果是(姓名,链接,性别)。但是,我需要电子邮件地址。如何从Facebook获取电子邮件地址?

1 个答案:

答案 0 :(得分:1)

要获得电子邮件访问权限,您需要编写自定义Facebook提供商。

已下载DotNetOpenAuth.AspNet.Clients.FacebookClient并添加了{ "scope", "email, read_stream" }

public sealed class CustomFacebookClient : OAuth2Client
{
    #region Constants and Fields

    /// <summary>
    /// The authorization endpoint.
    /// </summary>
    private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";

    /// <summary>
    /// The token endpoint.
    /// </summary>
    private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";

    /// <summary>
    /// The _app id.
    /// </summary>
    private readonly string appId;

    /// <summary>
    /// The _app secret.
    /// </summary>
    private readonly string appSecret;

    #endregion

    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="FacebookClient"/> class.
    /// </summary>
    /// <param name="appId">
    /// The app id.
    /// </param>
    /// <param name="appSecret">
    /// The app secret.
    /// </param>
    public CustomFacebookClient(string appId, string appSecret)
        : base("facebook")
    {
        Requires.NotNullOrEmpty(appId, "appId");
        Requires.NotNullOrEmpty(appSecret, "appSecret");

        this.appId = appId;
        this.appSecret = appSecret;
    }

    #endregion

    #region Methods

    /// <summary>
    /// The get service login url.
    /// </summary>
    /// <param name="returnUrl">
    /// The return url.
    /// </param>
    /// <returns>An absolute URI.</returns>
    protected override Uri GetServiceLoginUrl(Uri returnUrl)
    {
        // Note: Facebook doesn't like us to url-encode the redirect_uri value
        var builder = new UriBuilder(AuthorizationEndpoint);
        builder.AppendQueryArgs(
            new Dictionary<string, string> {
                { "client_id", this.appId },
                { "scope", "email, read_stream" },
                { "redirect_uri", returnUrl.AbsoluteUri }
            });
        return builder.Uri;
    }

    /// <summary>
    /// The get user data.
    /// </summary>
    /// <param name="accessToken">
    /// The access token.
    /// </param>
    /// <returns>A dictionary of profile data.</returns>
    protected override IDictionary<string, string> GetUserData(string accessToken)
    {
        FacebookGraphData graphData;
        var request =
            WebRequest.Create(
                "https://graph.facebook.com/me?access_token=" + FacebookClientHelper.EscapeUriDataStringRfc3986(accessToken));
        using (var response = request.GetResponse())
        {
            using (var responseStream = response.GetResponseStream())
            {


                graphData = FacebookClientHelper.Deserialize<FacebookGraphData>(responseStream);
            }
        }

        // this dictionary must contains 
        var userData = new Dictionary<string, string>();
        userData.AddItemIfNotEmpty("id", graphData.Id);
        userData.AddItemIfNotEmpty("username", graphData.Email);
        userData.AddItemIfNotEmpty("name", graphData.Name);
        userData.AddItemIfNotEmpty("link", graphData.Link == null ? null : graphData.Link.AbsoluteUri);
        userData.AddItemIfNotEmpty("gender", graphData.Gender);
        userData.AddItemIfNotEmpty("birthday", graphData.Birthday);
        userData.AddItemIfNotEmpty("email", graphData.Email);
        return userData;
    }

    /// <summary>
    /// Obtains an access token given an authorization code and callback URL.
    /// </summary>
    /// <param name="returnUrl">
    /// The return url.
    /// </param>
    /// <param name="authorizationCode">
    /// The authorization code.
    /// </param>
    /// <returns>
    /// The access token.
    /// </returns>
    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        // Note: Facebook doesn't like us to url-encode the redirect_uri value
        var builder = new UriBuilder(TokenEndpoint);
        builder.AppendQueryArgs(
            new Dictionary<string, string> {
                { "client_id", this.appId },
                { "redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri) },
                { "client_secret", this.appSecret },
                { "code", authorizationCode },
            });

        using (WebClient client = new WebClient())
        {
            string data = client.DownloadString(builder.Uri);
            if (string.IsNullOrEmpty(data))
            {
                return null;
            }

            var parsedQueryString = HttpUtility.ParseQueryString(data);
            return parsedQueryString["access_token"];
        }
    }

    /// <summary>
    /// Converts any % encoded values in the URL to uppercase.
    /// </summary>
    /// <param name="url">The URL string to normalize</param>
    /// <returns>The normalized url</returns>
    /// <example>NormalizeHexEncoding("Login.aspx?ReturnUrl=%2fAccount%2fManage.aspx") returns "Login.aspx?ReturnUrl=%2FAccount%2FManage.aspx"</example>
    /// <remarks>
    /// There is an issue in Facebook whereby it will rejects the redirect_uri value if
    /// the url contains lowercase % encoded values.
    /// </remarks>
    private static string NormalizeHexEncoding(string url)
    {
        var chars = url.ToCharArray();
        for (int i = 0; i < chars.Length - 2; i++)
        {
            if (chars[i] == '%')
            {
                chars[i + 1] = char.ToUpperInvariant(chars[i + 1]);
                chars[i + 2] = char.ToUpperInvariant(chars[i + 2]);
                i += 2;
            }
        }
        return new string(chars);
    }

    #endregion

}

此外,人们可以认为这可行:

var parameters = new Dictionary<string, object>();
parameters["scope"] = "email";

OAuthWebSecurity.RegisterFacebookClient(appId:  "appId", appSecret: "appSecret",
"facebook, parameters);

这不起作用。它为您的提供商提供了额外的数据,您可以在视图中显示提供商时使用这些数据。

<img src="@provder.ExtraData["icon"]"/>