.NET ASP.NET MVC应用程序Facebook的OAuth的定义与范围 [英] .NET ASP.NET MVC application Facebook OAuth with defined scope

查看:124
本文介绍了.NET ASP.NET MVC应用程序Facebook的OAuth的定义与范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是创建 .NET ASP.NET MVC 与Facebook的的OAuth 与确定的范围?

What is the easiest way to create .NET ASP.NET MVC application with Facebook OAuth with defined scope?

我试过很多例子。 OAuthWebSecurity.RegisterClient 不支持加入更多Facebook的范围。 Facebook应用程序模板创建一个画布我需要非帆布的应用程序。 FacebookScopedClient不充分,无法使用此修复工作。

I tried many examples. OAuthWebSecurity.RegisterClient doesn't support adding more Facebook scope. Facebook application template creates a canvas and I need non-canvas application. FacebookScopedClient is not full and wasn't able to work with this fix.

你有什么建议?

我也开放对JavaScript / jQuery的解决方案。

I also open for JavaScript/jQuery solutions.

推荐答案

也许我太晚了,但我前几天来到这个问题,我在网上找到了只有少数贫困的解决方案。所以我写了我自己的解决方案,我现在才可以发布了。

Probably I'm too late, but I came into this problem some days ago and I found only few poor solutions on the web. So I wrote my own solution and I can post it only now.

我把它做的最作业的DotNetOpenAuth.AspNet.Clients.OAuth2Client类的优势。我只说扩展到包括范围和额外的用户数据。

I took advantage of the DotNetOpenAuth.AspNet.Clients.OAuth2Client class which do the most of the job. I only extended that to include scope and extra user data.

public class FacebookExtendedClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client
{   
    protected FacebookClient facebookClient;
    protected string fields;
    protected string scope;
    protected Func<string, object, string> fieldTransformer;
    protected bool emailAsUsername;
    protected IDictionary<string, string> userData;

    private string[] splittedFields;
    private string[] splittedScope;

    protected const string serviceLoginBaseUrl = "https://www.facebook.com/dialog/oauth";
    protected const string serviceMeBaseUrl = "https://graph.facebook.com/me";
    protected const string serviceAccessTokenBaseUrl = "https://graph.facebook.com/oauth/access_token";

    /// <summary>
    /// Create an instrance of the class.
    /// </summary>
    /// <param name="appId">The App ID of the application used to connect to Facebook service.</param>
    /// <param name="appSecret">The App Secret of the application used to connect to Facebook service.</param>
    /// <param name="fields">
    /// String containing comma separated fields to add to the request.
    /// If empty the request will retrieve the default fields based of the specified scope.
    /// </param>
    /// <param name="fieldTransformer">
    /// Function to be applied to the values retrived from facebook.
    /// If null provided the method will try to cast values from object to string explicitly,
    /// an InvalidCastException will be thrown if the cast will not be possible.
    /// </param>
    /// <param name="scope">
    /// String containing comma separated permissions to add to the request.
    /// If empty the request will have the basic scope.
    /// </param>
    /// <param name="emailAsUsername">Makes the email of the facebook user used as authentication username.</param>
    public FacebookExtendedClient(string appId, string appSecret, string fields = "", Func<string, object, string> fieldTransformer = null, string scope = "", bool emailAsUsername = false)
        : base("facebook")
    {
        if (string.IsNullOrEmpty(appId))
            throw new ArgumentException("The appId argument can not be null or empty.", "appId");
        if (string.IsNullOrEmpty(appSecret))
            throw new ArgumentException("The appSecret argument can not be null or empty.", "appSecret");

        fields = fields.Replace(" ", "");
        scope = scope.Replace(" ", "");
        this.splittedFields = fields.Split(',');
        this.splittedScope = scope.Split(',');

        if (emailAsUsername == true && !this.splittedFields.Contains("email") && !this.splittedScope.Contains("email"))
            throw new ArgumentException("The scope argument must contain the 'email' permission and the 'email' field to allow emailAsUsername to true.", "scope");

        this.facebookClient = new FacebookClient();
        this.facebookClient.AppId = appId;
        this.facebookClient.AppSecret = appSecret;
        this.fields = fields;
        this.fieldTransformer = fieldTransformer;
        this.scope = scope;
        this.emailAsUsername = emailAsUsername;
    }

    public FacebookClient FacebookClient
    {
        get
        {
            return this.facebookClient;
        }
    }

    public IDictionary<string, string> UserData
    {
        get
        {
            return this.userData;
        }
    }

    protected override Uri GetServiceLoginUrl(Uri returnUrl)
    {
        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("redirect_uri", returnUrl.AbsoluteUri);

        if (!string.IsNullOrEmpty(this.scope))
            parameters.Add("scope", this.scope);

        return this.facebookClient.GetLoginUrl(parameters);
    }

    protected override IDictionary<string, string> GetUserData(string accessToken)
    {
        // This method makes the AuthenticationResult's UserName property be the facebook username of the logged user,
        // but if the facebook username is missing the facebook id will be used.
        // If emailAsUsername is true then AuthenticationResult's UserName property is the email retrieved from facebook
        // and the facebook username can be retrieved by the key "fb_username" in this.userData

        FacebookClient facebookClient = new FacebookClient(accessToken);

        var getResult = facebookClient.Get<IDictionary<string, object>>("me", new { fields = this.fields });
        Dictionary<string, string> result = new Dictionary<string, string>();

        if (this.fieldTransformer != null)
        {
            foreach (var pair in getResult)
                result.Add(pair.Key, this.fieldTransformer(pair.Key, pair.Value));
        }
        else
        {
            foreach (var pair in getResult)
            {
                string value = pair.Value.ToString();

                if (value == null)
                    throw new InvalidCastException("Cast not possible for the object associate to the key '" + pair.Key + "'.");

                result.Add(pair.Key, value);
            }
        }

        if (this.splittedFields.Contains("username"))
            result["fb_username"] = result["username"];

        if (this.emailAsUsername)
            result["username"] = result["email"];

        this.userData = result;

        return result;
    }

    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        UriBuilder builder = new UriBuilder(serviceAccessTokenBaseUrl);
        builder.Query = string.Format("client_id={0}&client_secret={1}&redirect_uri={2}&code={3}",
            this.facebookClient.AppId, this.facebookClient.AppSecret, HttpUtility.UrlEncode(Encoding.ASCII.GetBytes(returnUrl.AbsoluteUri)), authorizationCode);

        using (WebClient client = new WebClient())
        {
            string str = client.DownloadString(builder.Uri);

            if (string.IsNullOrEmpty(str))
                return null;

            return HttpUtility.ParseQueryString(str)["access_token"];
        }
    }
}

您可以使用它,以及在这样OAuthWebSecurity注册它(放RegisterAuth方法的Application_Start,就像是在InternetApplication模板):

You can use it as well registering it in OAuthWebSecurity like this (put RegisterAuth method in Application_Start, like it is in the InternetApplication template):

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        configuration.LoadFromAppSettings();

        OAuthWebSecurity.RegisterClient(new FacebookExtendedClient(
            "##YOUR_APP_ID##",
            "##YOUR_APP_SECRET##",
            "id,first_name,last_name,link,username,gender,email,age_range,picture.height(200)",
            new Func<string, object, string>(fieldsTransformer),
            "email"));
    }

    private static string fieldsTransformer(string key, object value)
    {
        switch (key)
        {
            case "picture":
                var data = (value as IDictionary<string, object>)["data"] as IDictionary<string, object>;
                return data["url"].ToString();
            case "age_range":
                var min = (value as IDictionary<string, object>)["min"];
                return min.ToString();
            default:
                return value.ToString();
        }
    }
}

正如在fieldsTransformer会得到一个键并选择了值的foreach字段上述方法的例子中看到的,在这种情况下,将改变由实为图片retrived对象进入画面的URL。值的这是一种便捷的方法,如果提供的函数功能参数为空,则JSON重新presentation对象将被保存。

As you can see in the example above the method fieldsTransformer will get the key and the value foreach field selected, in this case it will transform the object retrived by facebook for the picture into the url of the picture. This is a convenience method, if null is provided for the Func parameter, the JSON representation of the values object will be saved.

在以后检索客户端的信息,登录后,可以这样进行:

Retrieve the client information later, after the login, can be done like this:

[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        IDictionary<string, string> userData = (OAuthWebSecurity.GetOAuthClientData("facebook").AuthenticationClient as FacebookExtendedClient).UserData;
        string email = userData["email"];

        // If leave null the fieldTransform of the client you can access to complex properties like this:
        JObject picture = JObject.Parse(userData["picture"]);
        string url = (picture["data"] as JObject)["url"].ToString();

        ViewBag.Email = userData["email"];
        ViewBag.PictureUrl = url;
        return View();
    }
}

希望你喜欢这个code,哪怕是有点晚了! :)

Hope you enjoy this code, even if it is a bit late! :)

这篇关于.NET ASP.NET MVC应用程序Facebook的OAuth的定义与范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆