LSTANCZYK
3/21/2017 - 5:00 PM

FacebookAuth.cs

using Facebook;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web.Mvc;

namespace Auction.Web.Areas.Facebook
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    public class FacebookAuthAttribute : ActionFilterAttribute
    {
        private readonly string[] Scope = new[] { "email" /*, "publish_actions" */ };

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var viewBag = filterContext.Controller.ViewBag;
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                var client = new FacebookClient();
                Uri redirectUri = new Uri("https://apps.facebook.com/" + ConfigurationManager.AppSettings["FacebookNamespace"]);
                viewBag.LoginUrl = GetLoginUrl(client, redirectUri, Scope);
            }
            viewBag.AskCookieConsent = false;
            viewBag.HasCookieConsent = true;

            base.OnActionExecuting(filterContext);
        }


        private Uri GetLoginUrl(FacebookClient client, Uri redirectUri, string[] scope = null, string state = null, bool isMobile = false)
        {
            if (redirectUri == null)
                throw new ArgumentNullException("redirectUri");

            var parameters = new Dictionary<string, object>();
            parameters["client_id"] = ConfigurationManager.AppSettings["FacebookAppId"];
            parameters["redirect_uri"] = redirectUri.ToString();

            if (scope != null && scope.Length > 0)
                parameters["scope"] = scope;
            if (!string.IsNullOrWhiteSpace(state))
                parameters["state"] = state;
            if (isMobile)
                parameters["mobile"] = true;

            return client.GetLoginUrl(parameters);
        }
    }
}
using Auction.Web.Domain;
using Auction.Web.Domain.Commands;
using Auction.Web.Domain.Entities;
using Auction.Web.Domain.Queries;
using Facebook;
using Microsoft.Web.WebPages.OAuth;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Web;
using System.Web.Routing;

namespace Auction.Web.Areas.Facebook
{
    public static class FacebookAuth
    {
        public const string facebookCustomAuth = "FacebookCustomAuth";
        public const string FacebookAccessToken = "http://www.facebook.com/claims/AccessToken";


        public static bool InFacebookArea(HttpRequest request)
        {
            return (request.Url.Segments.Length >= 2 && request.Url.Segments[1].TrimEnd('/').Equals("facebook", StringComparison.InvariantCultureIgnoreCase));
        }

        public static bool InFacebookArea(HttpRequestBase request)
        {
            return (request.Url.Segments.Length >= 2 && request.Url.Segments[1].TrimEnd('/').Equals("facebook", StringComparison.InvariantCultureIgnoreCase));
        }

        public static RouteValueDictionary CombineRouteValues(HttpContextBase context, RouteValueDictionary routeValues)
        {
            if (context.User != null && context.User.Identity != null && context.User.Identity.AuthenticationType == facebookCustomAuth)
            {
                var principal = context.User as ClaimsPrincipal;
                routeValues["username"] = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value;
                routeValues["token"] = principal.Claims.FirstOrDefault(c => c.Type == FacebookAccessToken).Value;
                routeValues["area"] = "Facebook";
            }

            return routeValues;
        }

        public static RouteValueDictionary CombineRouteValues(HttpContextBase context, object routeValues)
        {
            var routeValueResult = new RouteValueDictionary(routeValues);
            return CombineRouteValues(context, routeValueResult);
        }

        public static Uri GetLoginUrl(Uri requestUri, string[] scope = null, string state = null, bool isMobile = false)
        {
            string redirectUri = "https://apps.facebook.com/" + ConfigurationManager.AppSettings["FacebookNamespace"];

            var parameters = new Dictionary<string, object>();

            parameters["client_id"] = ConfigurationManager.AppSettings["FacebookAppId"];
            // TODO: combine requestUri
            parameters["redirect_uri"] = redirectUri.ToString();

            if (scope != null && scope.Length > 0)
                parameters["scope"] = scope;
            if (!string.IsNullOrWhiteSpace(state))
                parameters["state"] = state;
            if (isMobile)
                parameters["mobile"] = true;

            var client = new FacebookClient();
            return client.GetLoginUrl(parameters);
        }


        public static void AuthenticateRequest(HttpApplication context)
        {
            // int userId;
            string userName;
            string authToken;
            HttpRequest request = context.Request;

            // Facebook canvas apps lives inside an iframe, therefore when third party cookies are blocked, sessions do not work!
            // Facebook posts user data in its first iframe request to the app. 
            // We get the fb auth_token and our userid, save those in the HttpContext and pass them in each and every link or form action that happen inside /Facebook
            if (InFacebookArea(request))
            {
                if (request["token"] != null && request["username"] != null)
                {
                    // Save them into the http context
                    authToken = request["token"].ToString();
                    userName = request["username"].ToString();

                    if (context.Context.User == null)
                    {
                        // user is not authenticated yet -> set user to facebook principal
                        //var userIdentity = new FacebookIdentity(userId, authToken, "Facebook user");
                        //var principal = new FacebookPrincipal(userIdentity);
                        var userIdentity = new ClaimsIdentity(new Claim[] 
                        { 
                            new Claim(ClaimTypes.Name, userName), 
                            new Claim(FacebookAccessToken, authToken), 
                            new Claim(ClaimTypes.Role, "Facebook")
                        }, facebookCustomAuth);
                        var principal = new ClaimsPrincipal(new[] { userIdentity });
                        context.Context.User = principal;
                        Thread.CurrentPrincipal = principal;
                    }
                }
                else if (request["signed_request"] != null)
                {
                    var client = new FacebookClient();

                    var signedRequest = client.ParseSignedRequest(ConfigurationManager.AppSettings["FacebookAppSecret"], request["signed_request"]);
                    if (signedRequest == null)
                        throw new ArgumentNullException("signedRequest");

                    var dict = signedRequest as IDictionary<string, object>;
                    if (dict != null)
                    {
                        if (dict.ContainsKey("oauth_token"))
                        {
                            authToken = (string)dict["oauth_token"];

                            client.AccessToken = authToken;
                            dynamic result = client.Get("me", new { fields = new[] { "email" } });
                            string fbUserId = result.id;

                            using (var ctx = new DomainContext())
                            {
                                var user = ctx.Query(new GetUserByClaims("facebook", result.id));
                                if (user != null)
                                {
                                    // returning user -> get id from database
                                    userName = user.UserName;
                                }
                                else
                                {
                                    // check if we have this email in our database already (from normal site)
                                    user = ctx.Query(new GetUserByName(result.email));
                                    if (user != null)
                                    {
                                        userName = user.UserName;
                                    }
                                    else
                                    {
                                        // new user -> save to database with email as the unique name 
                                        userName = result.email;
                                        // will throw if username exists
                                        ctx.ExecuteCommand(new CreateUser(new UserProfile { UserName = userName }));
                                    }
                                    OAuthWebSecurity.CreateOrUpdateAccount("facebook", fbUserId, userName); // links OAuth to UserProfile based on the username, not on UserId
                                    OAuthWebSecurity.Login("facebook", fbUserId, createPersistentCookie: false);
                                }
                            }

                            if (context.Context.User == null)
                            {
                                // Now set the HttpContext.User.Identity
                                var userIdentity = new ClaimsIdentity(new Claim[] 
                                { 
                                    new Claim(ClaimTypes.Name, userName),
                                    new Claim(FacebookAccessToken, authToken),
                                    new Claim(ClaimTypes.Role, "Facebook")
                                }, facebookCustomAuth);
                                var principal = new ClaimsPrincipal(new[] { userIdentity });
                                context.Context.User = principal;
                                Thread.CurrentPrincipal = principal;
                            }
                        }
                    }
                    else
                    {
                        throw new ArgumentException("Cannot read signed_request!");
                    }
                }
            }
        }
    }
}