ASP.NET Identity + Facebook login: Pass in “rerequ

2020-03-31 08:26发布

问题:

(Using ASP.NET Identity 2.1, Microsoft.Owin.Security.Facebook 3.0.1 in a Web API project)

From here: https://developers.facebook.com/docs/facebook-login/login-flow-for-web/v2.2

This is because once someone has declined a permission, the Login Dialog will not re-ask them for it unless you explicitly tell the dialog you're re-asking for a declined permission.

You do this by adding the auth_type: rerequest flag to your FB.login() call:

FB.login(
  function(response) {
    console.log(response);
  },
  {
    scope: 'user_likes',
    auth_type: 'rerequest'
  }
);

When you do that, the Login Dialog will re-ask for the declined permission. The dialog will look very much like the dialog in the section on re-asking for permissions but will let you re-ask for a declined permission.

So, using ASP.NET Identity's integration with Facebook login, I know how to pass in the requested scope, but if the user declines the permission, I need to pass in the extra parameter "auth_type" : 'rerequest." How do I do that?

回答1:

You first add your custom FacebookAuthenticationProvider

    public class FacebookProvider : FacebookAuthenticationProvider
    {
        public override void ApplyRedirect(FacebookApplyRedirectContext context)
        {
            //To handle rerequest to give some permission
            string authType = string.Empty;
            if (context.Properties.Dictionary.ContainsKey("auth_type"))
            {
                authType = string.Format("&auth_type={0}", context.Properties.Dictionary["auth_type"]);
            }
            //If you have popup loggin add &display=popup
            context.Response.Redirect(string.Format("{0}{1}{2}", context.RedirectUri, "&display=popup", authType));
        }
    }

now in the startup you need to use this provider

    var options = new FacebookAuthenticationOptions
    {
        AppId = "appid",
        AppSecret = "secret",

        Provider = new FacebookProvider
        {
            OnAuthenticated = async context =>
            {
                foreach (var x in context.User)
                {
                    if (x.Key == "birthday")
                    {
                        context.Identity.AddClaim(new Claim("dateofbirth", x.Value.ToString()));
                    }
                    else
                    {
                        context.Identity.AddClaim(new Claim(x.Key, x.Value.ToString()));
                    }
                }
                context.Identity.AddClaim(new Claim("fb_accecctoken", context.AccessToken));

                await Task.FromResult(context);
            }

        }
    };
    options.Scope.Add("public_profile");
    options.Scope.Add("email");
    options.Scope.Add("user_birthday");
    options.Scope.Add("user_location");
    app.UseFacebookAuthentication(options);

and finally in your account controller you need to set auth_type when you need

    private const string XsrfKey = "xsrfkey";

    internal class ChallengeResult : HttpUnauthorizedResult
    {
        public ChallengeResult(string provider, string redirectUri)
            : this(provider, redirectUri, null, false)
        {
        }

        public ChallengeResult(string provider, string redirectUri, string userId, bool isRerequest)
        {
            LoginProvider = provider;
            RedirectUri = redirectUri;
            UserId = userId;
            IsRerequest = isRerequest;
        }

        public string LoginProvider { get; set; }
        public string RedirectUri { get; set; }
        public string UserId { get; set; }
        public bool IsRerequest { get; set; }

        public override void ExecuteResult(ControllerContext context)
        {
            var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
            if (UserId != null)
            {
                properties.Dictionary[XsrfKey] = UserId;
            }
            if (IsRerequest)
            {
                properties.Dictionary["auth_type"] = "rerequest";
            }
            context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
        }
    }


回答2:

I had the same issue when I wanted to ensure the user had accepted all my permissions. As you probably know this can be detected by calling the /me/permissions url.

So I eventually solved it by simply deleting my app from the user's account.

You can do so by doing a DELETE request on the /me/permissions URL as documented here.

This will remove all permissions you requested from the user, so next time you try authenticating him through Facebook, the prompt appears again.