Лучшая практика для приложения iFrame + Внешняя аутентификация для Facebook с двойным использованием - PullRequest
3 голосов
/ 27 декабря 2010

Хорошо, если файлы cookie запрещены, мне нужно немного советов о том, как лучше всего реализовать создаваемые приложения.

Сценарий состоит в том, что я пытаюсь создать одно приложение MVC Asp.Net, которое может аутентифицировать пользователя независимо от того, посещает ли пользователь сайт напрямую или через iFrame в Facebook. Существуют отдельные действия (фактически, в отдельных контроллерах) для получения INTO приложения в зависимости от того, входит ли пользователь через Facebook или нет, но в приложении Facebook также есть места, где я открываю новое окно для «расширенной» функциональности. в других областях приложения, которые не могут хорошо работать в iFrame. Предполагается, что переход без проблем. В настоящее время он работает довольно хорошо, используя куки, но я из нескольких источников, что это не очень хорошая вещь для приложений iFrame. Однако я не совсем уверен, что это значит.

Без файлов cookie можно ли как-нибудь получить доступ к токену аутентификации на стороне сервера? Если нет, то каков «правильный» способ справиться с этим. Нужно ли прибегать к ручному синтаксическому анализу токена с помощью JS API и отправке AJAX-уведомления на сервер о том, что пользователь прошел аутентификацию и создал токен авторизации форм? Будет ли атрибут CanvasAuthorize работать без файлов cookie? Прямо сейчас я добавил код в событие FormsAuthentication_OnAuthenticate в Global.asax для создания токена проверки подлинности форм, если пользователь вошел в систему через Facebook (и правильно связан с действительным пользователем во внешнем приложении) следующим образом:

protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs args)
{
    if (FormsAuthentication.CookiesSupported)
    {
        if (Request.Cookies[FormsAuthentication.FormsCookieName] == null)
        {
            // Attempt to authenticate using Facebook
            try
            {
                FacebookApp fbApp = new FacebookApp();
                if (fbApp.Session != null)
                {
                    dynamic me = fbApp.Get("me");
                    String fbID = "" + me.id;
                    MembershipUser mUser = AppMembershipProvider.GetUserByFacebookID(fbID);
                    if (mUser != null)
                    {
                        FormsAuthentication.SetAuthCookie(mUser.UserName, false);
                        AppMembershipProvider.UpdateLastLogin(mUser.UserName);
                        Session["FacebookLogin"] = true;
                    }
                }
            }
            catch (Exception e)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(e);
            }
        }
    }
    else
    {
        throw new HttpException("Cookieless Forms Authentication is not " +
                                "supported for this application.");
    }
}

Нужно ли мне это изменить?

Извините, если это базовые знания, но я не понимаю, как лучше всего это реализовать. Спасибо!

Ответы [ 2 ]

3 голосов
/ 27 декабря 2010

Во-первых, позвольте мне решить проблему с файлами cookie. Итак, когда я говорю, чтобы не использовать куки в iFrames, я говорю это по нескольким причинам. Во-первых, в IE есть некоторые проблемы с безопасностью. Вам нужно добавить следующий заголовок в ваше приложение, чтобы куки правильно работали внутри фреймов:

P3P: CP="CAO PSA OUR"

Вторая большая проблема с файлами cookie в приложениях iframe - это Safari. Из-за настроек безопасности в Safari файлы cookie не могут быть созданы с помощью iframes. Таким образом, вы не сможете полагаться на куки для аутентификации внутри iframes.

Если вы используете приложение внутри и вне iframe, у вас должна быть включена поддержка файлов cookie. Тем не менее, ваше приложение должно быть спроектировано так, чтобы обходить проблемы iframe. Это будет трудная часть.

Самая надежная аутентификация в приложениях iframe - это метод подписанного запроса. То, что происходит, это то, что Facebook добавит параметр запроса к вашему URL, когда URL будет отображен внутри iframe. Этот параметр запроса содержит сеанс пользователя. Facebook C # SDK обрабатывает чтение для вас, так что вам не нужно анализировать его и т. Д. Но вы должны знать, что он есть. Если вы просматриваете URL-адрес входящего запроса вашего приложения iframe в Facebook, вы увидите что-то вроде http://www.mysite.com/page/?signed_request={blahblahblah}.

Таким образом, ключ заключается в том, что вам нужно убедиться, что если вы находитесь в iframe, вы сохраните это значение? Signature_request в URL.

Вы можете сделать это несколькими способами. Во-первых, вы можете использовать методы CanvasRedirect. Это методы расширения для System.Web.Mvc.Controller в пространстве имен Facebook.Web.Mvc. Переадресация холста использует JavaScript для перенаправления вашей страницы в верхний URL. Таким образом, Facebook фактически обрабатывает перенаправления и всегда добавляет подписанный запрос в ваш URL-адрес iframe. Проблема для вас в том, что этот метод перенаправления будет работать только в iframe, а не снаружи.

Вторым способом было бы вручную добавить подписанный запрос к URL при перенаправлении. Вы бы сделали что-то вроде:

public ActionResult Something () { return RedirectToAction ("что-то", new {signature_request = Request.Querystring ["signature_requets"]); }

Есть и другие способы, такие как хранение данных в сеансе или что-то еще, но я бы не рекомендовал идти по этому пути.

То, что вы делаете, определенно является продвинутым сенарио, но, надеюсь, вышеизложенное поможет вам двигаться в правильном направлении. Не стесняйтесь обращаться ко мне напрямую, если у вас есть какие-либо вопросы. nathan@ntotten.com или @ntotten в твиттере.

1 голос
/ 06 января 2011

Я нахожусь с вами в подобной ситуации. Что я делаю, чтобы справиться с различными ситуациями, которые могут возникнуть:

  • Включить куки в C # и JavaScript SDK.
  • Создайте собственный фильтр действий, который наследует от FacebookAuthorizeAttribute и переопределяет Метод HandleUnauthorizedRequest для перенаправить на соединение страница авторизации или действие украшен CanvasAuthorizeAttribute.
  • Передайте подписанный запрос (холст приложение) или auth_token (подключиться app) в качестве параметра строки запроса для все.
  • Проверка на нулевые сеансы и oauth токены, которые не соответствуют тому, что было передается в строке запроса.

Суть в том, чтобы убедиться, что токены сеанса и oauth являются действительными. Когда в Facebook подписанный запрос будет гарантировать, что это правда. Передав токен со своей страницы авторизации подключения, вы можете убедиться, что у вас есть действительный токен для внедрения в конструктор FacebookApp.

    public class FbAuthenticateAttribute : FacebookAuthorizeAttribute
    {
        private FacebookApp _fbApp;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            var accessToken = filterContext.HttpContext.Request.Params["access_token"];
            if (FacebookApp.AccessToken != accessToken && !string.IsNullOrEmpty(accessToken))
            {
                _fbApp = new FacebookApp(accessToken);
            }
            else
            {
                _fbApp = FacebookApp;
            }
            filterContext.Controller.ViewBag.Context = GetContext().ToString();
            filterContext.RequestContext.HttpContext.Response.AppendHeader("p3p", "CP=\"CAO PSA OUR\"");
            try
            {
                dynamic user = _fbApp.Get("me");
                var signedRequest = filterContext.HttpContext.Request.Params["signed_request"];
                filterContext.Controller.ViewBag.QueryString = string.IsNullOrEmpty(signedRequest)
                                          ? "?access_token=" + _fbApp.AccessToken
                                          : "?signed_request=" + signedRequest;
            }
            catch (Exception ex)
            {
                string url = GetRedirectUrl(filterContext);
                filterContext.Result = new RedirectResult(url);
            }
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            string url = GetRedirectUrl(filterContext);
            filterContext.Result = new RedirectResult(url);
        }

        private string GetRedirectUrl(ControllerContext filterContext)
        {
            return new UrlHelper(filterContext.RequestContext).Action(GetRedirectAction(GetContext()), "Authentication");
        }

        private Enums.AppContext GetContext()
        {
            //Note: can't rely on this alone - find something more robust
            return FacebookApp.SignedRequest == null ? Enums.AppContext.FBWeb : Enums.AppContext.FBApp;
        }

        private string GetRedirectAction(Enums.AppContext context)
        {
            return context == Enums.AppContext.FBWeb ? "ConnectAuthenticate" : "Authenticate";
        }
    }

Это определенно может быть связано с рефакторингом, но у него все еще есть проблемы, но это лучшее решение, которое я нашел до сих пор.

...