Last active
March 21, 2017 17:00
-
-
Save Maarten88/5930554 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment