使用OAuthWebSecurity和Facebook强制重新认证

Force re-authentication using OAuthWebSecurity with Facebook
2021-06-10
  •  译文(汉语)
  •  原文(英语)

我的网站使用的是Facebook,因为它是oauth提供商.用户将可以通过我的网站购买商品,因此即使他们已经与facebook进行了活跃的交流,我也想强迫他们进行身份验证.

讨论重新认证的facebook api文档中找到了此链接,但无法使其与我的mvc应用程序一起使用.有人知道这是否可能吗?

var extra = new Dictionary<string, object>();
extra.Add("auth_type", "reauthenticate");

OAuthWebSecurity.RegisterFacebookClient(
            appId: "**********",
            appSecret: "**********************",
            displayName: "",
            extraData: extra);  
解决过程1

找到了解决方案.我必须创建自己的客户端,而不是使用由提供的默认客户端OAuthWebSecurity.RegisterFacebookClient

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Helpers;

namespace Namespace.Helpers
{
    public class MyFacebookClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client
    {
        private const string AuthorizationEP = "https://www.facebook.com/dialog/oauth";
        private const string TokenEP = "https://graph.facebook.com/oauth/access_token";
        private readonly string _appId;
        private readonly string _appSecret;

        public MyFacebookClient(string appId, string appSecret)
            : base("facebook")
        {
            this._appId = appId;
            this._appSecret = appSecret;
        }


        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            return new Uri(
                        AuthorizationEP
                        + "?client_id=" + this._appId
                        + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                        + "&scope=email,user_about_me"
                        + "&display=page"
                        + "&auth_type=reauthenticate"
                    );
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                "https://graph.facebook.com/me?access_token=" + accessToken
            );
            dynamic data = Json.Decode(content);
            return new Dictionary<string, string> {
                {
                    "id",
                    data.id
                },
                {
                    "name",
                    data.name
                },
                {
                    "photo",
                    "https://graph.facebook.com/" + data.id + "/picture"
                },
                {
                    "email",
                    data.email
                }
            };
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                TokenEP
                + "?client_id=" + this._appId
                + "&client_secret=" + this._appSecret
                + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                + "&code=" + authorizationCode
            );

            NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(content);
            if (nameValueCollection != null)
            {
                string result = nameValueCollection["access_token"];
                return result;
            }
            return null;
        }
    }
}

然后在AuthConfig.cs中...

 OAuthWebSecurity.RegisterClient(
                new MyFacebookClient(
                    appId: "xxxxxxxxxx", 
                    appSecret: "xxxxxxxxxxxxxxxx"),
                "facebook", null
            );
速聊1:
如果此答案对您不起作用,请参阅我的答复,因为在撰写本文时它是正确的,但需要更新.
解决过程2

请注意,当v2.3成为您可以访问的最低版本时,如果您的Facebook身份验证停止工作(非版本化的调用将获得应用程序可以访问的最低版本),则发生这种情况的提示.API现在返回JSON而不是名称值对,因此您必须更新@Ben Tidman上面显示的QueryAccessToken方法

下面是更新的方法

protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                TokenEP
                + "?client_id=" + this._appId
                + "&client_secret=" + this._appSecret
                + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                + "&code=" + authorizationCode
            );

            dynamic json = System.Web.Helpers.Json.Decode(content);
            if (json != null)
            {
                string result = json.access_token;
                return result;
            }
            return null;
        }
解决过程3

使用MyFacebookClient实现存在一个问题.可能有人尝试实现它时遇到了错误:

给定的键在字典中不存在

尝试在ActionController中调用ExternalLoginCallback方法.

方法出现错误时

OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

叫做.

为了使其工作,必须重写方法VerifyAuthentication.特别是

public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl);

抽象类OAuth2Client的重载.

如果使用以下命令:

 public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
    {
        string code = context.Request.QueryString["code"];

        string rawUrl = context.Request.Url.OriginalString;
        //From this we need to remove code portion
        rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");

        IDictionary<string, string> userData =    GetUserData(QueryAccessToken(returnPageUrl, code));

        if (userData == null)
            return new AuthenticationResult(false, ProviderName, null, null, null);


        AuthenticationResult result = new AuthenticationResult(true, ProviderName, userData["id"], userData["name"], userData);
        userData.Remove("id");
        userData.Remove("name");
        return result;
    }
}

最终,您将以正确的方式获得调用的方法,并且不会引发任何异常.

My website is using facebook as it's oauth provider. Users will be able to buy things through my site so I want to force them to authenticate even if they already have an active session with facebook.

I found this link in facebook's api documentation that discusses reauthentication but I can't get it to work with my mvc app. Anyone know if this is possible?

var extra = new Dictionary<string, object>();
extra.Add("auth_type", "reauthenticate");

OAuthWebSecurity.RegisterFacebookClient(
            appId: "**********",
            appSecret: "**********************",
            displayName: "",
            extraData: extra);  
Solutions1

Found the solution. I had to create my own client instead of using the default one provided by OAuthWebSecurity.RegisterFacebookClient

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Helpers;

namespace Namespace.Helpers
{
    public class MyFacebookClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client
    {
        private const string AuthorizationEP = "https://www.facebook.com/dialog/oauth";
        private const string TokenEP = "https://graph.facebook.com/oauth/access_token";
        private readonly string _appId;
        private readonly string _appSecret;

        public MyFacebookClient(string appId, string appSecret)
            : base("facebook")
        {
            this._appId = appId;
            this._appSecret = appSecret;
        }


        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            return new Uri(
                        AuthorizationEP
                        + "?client_id=" + this._appId
                        + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                        + "&scope=email,user_about_me"
                        + "&display=page"
                        + "&auth_type=reauthenticate"
                    );
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                "https://graph.facebook.com/me?access_token=" + accessToken
            );
            dynamic data = Json.Decode(content);
            return new Dictionary<string, string> {
                {
                    "id",
                    data.id
                },
                {
                    "name",
                    data.name
                },
                {
                    "photo",
                    "https://graph.facebook.com/" + data.id + "/picture"
                },
                {
                    "email",
                    data.email
                }
            };
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                TokenEP
                + "?client_id=" + this._appId
                + "&client_secret=" + this._appSecret
                + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                + "&code=" + authorizationCode
            );

            NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(content);
            if (nameValueCollection != null)
            {
                string result = nameValueCollection["access_token"];
                return result;
            }
            return null;
        }
    }
}

and then in AuthConfig.cs...

 OAuthWebSecurity.RegisterClient(
                new MyFacebookClient(
                    appId: "xxxxxxxxxx", 
                    appSecret: "xxxxxxxxxxxxxxxx"),
                "facebook", null
            );
Talk1:
See my response if this answer doesn't work for you as it was correct at the time of writing but needs to be updated.
Solutions2

As a note to those that happen upon this if your Facebook Authentication stopped working when v2.3 became the lowest version you have access to (non versioned calls get the lowest version an app has access to). The API now returns JSON and not name value pairs so you have to update the QueryAccessToken method shown above by @Ben Tidman

Below is the updated method

protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            WebClient client = new WebClient();
            string content = client.DownloadString(
                TokenEP
                + "?client_id=" + this._appId
                + "&client_secret=" + this._appSecret
                + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
                + "&code=" + authorizationCode
            );

            dynamic json = System.Web.Helpers.Json.Decode(content);
            if (json != null)
            {
                string result = json.access_token;
                return result;
            }
            return null;
        }
Solutions3

There's one issue in using the MyFacebookClient implementation. Probably someone tryin to implement it came across the error:

The given key was not present in the dictionary

attempting to call the ExternalLoginCallback method in ActionController.

The error raises when the method

OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

is called.

In order to get it working the method VerifyAuthentication has to be overridden. In particular the

public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl);

overload of the abstract class OAuth2Client.

If you use the following:

 public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
    {
        string code = context.Request.QueryString["code"];

        string rawUrl = context.Request.Url.OriginalString;
        //From this we need to remove code portion
        rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");

        IDictionary<string, string> userData =    GetUserData(QueryAccessToken(returnPageUrl, code));

        if (userData == null)
            return new AuthenticationResult(false, ProviderName, null, null, null);


        AuthenticationResult result = new AuthenticationResult(true, ProviderName, userData["id"], userData["name"], userData);
        userData.Remove("id");
        userData.Remove("name");
        return result;
    }
}

finally you get the method called in the right way and no excpetion is thrown.

转载于:https://stackoverflow.com/questions/19063508/force-re-authentication-using-oauthwebsecurity-with-facebook

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入