Asp.net mvc 3 可以ASP.NETMVC4';打开一个弹出窗口

Asp.net mvc 3 可以ASP.NETMVC4';打开一个弹出窗口,asp.net-mvc-3,asp.net-mvc-4,oauth-2.0,facebook-oauth,oauth-provider,Asp.net Mvc 3,Asp.net Mvc 4,Oauth 2.0,Facebook Oauth,Oauth Provider,我试图弄清楚如何使用ASP.NETMVC4的新OAuthWebSecurity功能。当点击facebook或twitter外部登录按钮时,是否可以将表单发布到弹出窗口,而不是刷新当前页面?在使用Javascript之前,我已经将oauth与Twitter和Facebook结合使用,外部身份验证将在弹出窗口中进行。异步返回结果后,弹出窗口将关闭。我可以使用MVC4的新OAuthWebSecurity功能做类似的事情吗?谢谢。解决这个问题有几个方面: 打开弹出窗口以容纳身份验证序列 验证完成后关闭弹

我试图弄清楚如何使用ASP.NETMVC4的新OAuthWebSecurity功能。当点击facebook或twitter外部登录按钮时,是否可以将表单发布到弹出窗口,而不是刷新当前页面?在使用Javascript之前,我已经将oauth与Twitter和Facebook结合使用,外部身份验证将在弹出窗口中进行。异步返回结果后,弹出窗口将关闭。我可以使用MVC4的新OAuthWebSecurity功能做类似的事情吗?谢谢。

解决这个问题有几个方面:

  • 打开弹出窗口以容纳身份验证序列
  • 验证完成后关闭弹出窗口
  • 处理身份验证失败
  • 更新父页面以反映用户已通过身份验证的事实
  • 以下是我如何使用MVC4
    互联网应用程序
    模板作为起点来实现这些需求:

    要在弹出窗口中启动身份验证序列(而不是重定向到新页面),您需要修改
    \u ExternalLoginListPartial.cshtml
    ,以便其表单回发以JavaScript函数启动的弹出窗口为目标:

    @model ICollection<AuthenticationClientData>
    
    @if (Model.Count == 0)
    {
        <div class="message-info">
            <p>There are no external authentication services configured. See <a href="http://go.microsoft.com/fwlink/?LinkId=252166">this article</a>
            for details on setting up this ASP.NET application to support logging in via external services.</p>
        </div>
    }
    else
    {
        <form id="login-launch" action="@Url.Action("ExternalLogin", "Account")" method="POST" target="login-popup" onsubmit="invokeLogin();">
            @Html.AntiForgeryToken()
            <fieldset id="socialLoginList">
                <input type="hidden" id="provider" name="provider" />
                <input type="hidden" name="returnUrl" value="@ViewBag.ReturnUrl"/>
                <p>
                    @foreach (var p in OAuthWebSecurity.RegisteredClientData)
                    {
                        <button type="submit" onclick="$('#provider').attr('value', '@p.DisplayName'); $('#login-launch').submit();" title="Log in using @p.DisplayName">@p.DisplayName</button>
                    }
                </p>
            </fieldset>
        </form>
    }
    
    <script type="text/javascript">
        function invokeLogin() {
            var chrome = 100;
            var width = 500;
            var height = 500;
            var left = (screen.width - width) / 2;
            var top = (screen.height - height - chrome) / 2;
            var options = "status=0,toolbar=0,location=1,resizable=1,scrollbars=1,left=" + left + ",top=" + top + ",width=" + width + ",height=" + height;
            window.open("about:blank", "login-popup", options);
        }
    </script>
    
    此操作方法是原始项目模板附带的
    ExternalLoginCallback()
    方法的简化版本。与原始实现不同,此简化示例不支持在创建新帐户时允许用户定义个性化用户名,也不允许多个OAuth或OpenID帐户与单个MVC用户帐户关联。但是,通过扩展上述模式以合并原始模板的更复杂逻辑,这些功能是可行的

    上述操作方法的一个关键设计特性是,无论身份验证尝试的结果如何,它始终返回相同的视图。这是必要的,因为返回的视图包含关闭身份验证弹出窗口并调用父页面中任何必需的后续操作的JavaScript。因此,如果修改上述模式,则必须确保每个代码路径都返回
    LoginResult
    视图的实例,并根据身份验证的结果正确填充

    以下是
    Loginresult
    视图的标记:

    @model LoginResultViewModel
    @{
        Layout = null;
    
        var success = Model.Success ? "true" : "false";
        var returnUrl = Model.ReturnUrl == null ? "null" : string.Format("'{0}'", Model.ReturnUrl);
    }
    
    <!DOCTYPE html>
    <html>
    <head>
        <script type="text/javascript">
            if (window.opener && window.opener.loginCallback) {
                window.opener.loginCallback(@success, @Html.Raw(returnUrl));
            }
    
            window.close();
        </script>
    </head>
    </html>
    
    [HttpGet]
    public ActionResult LoginPartial()
    {
        if (Request.IsAjaxRequest())
        {
            return View("_LoginPartial");
        }
    
        return new EmptyResult();
    }
    
    有了上述所有元素,就可以启动在弹出窗口中执行的身份验证序列,该窗口在序列完成时自动关闭。如果身份验证成功,用户将在此时登录,如果启动时返回URL(如果由对受
    [Authorize]
    属性保护的操作方法的请求触发,则会自动发生),则父页面将重定向到最初请求的URL

    但是,如果用户明确启动了身份验证(例如,通过访问登录页面),则父页面将不会重定向,因此可能需要部分页面更新以反映用户现在已登录的事实。在MVC模板示例中,有必要更新页面以显示用户的姓名和一个
    注销
    按钮,而不是
    登录
    注册
    按钮

    这可以通过在布局视图中定义JavaScript回调函数来实现,该函数由验证弹出窗口执行的JavaScript调用:

    <script type="text/javascript">
        function loginCallback(success, returnUrl) {
            if (returnUrl) {
                window.location.href = returnUrl;
            } else {
                $.ajax({
                    url: '@Url.Action("LoginPartial", "Account")',
                    success: function (result) {
                        $('#login').html(result);
                    }
                });
            }
        }
    </script>
    
    需要对原始项目模板进行最后一次修改。必须修改
    \u LoginPartial
    视图,以便在没有布局视图的情况下进行渲染:

    @{
        Layout = null;
    }
    

    杰出的如果登录时没有返回URL,那么让页面完全重新加载通常会更安全吗?@IDisposable-是的,这种方法更简单,可以让您消除Ajax调用的脚本代码和完成部分页面更新的相关操作方法。但是,由于父页面在验证序列期间没有与服务器直接交互,因此仍然需要在关闭前通过弹出窗口使用脚本调用触发重定向。哇,非常感谢Tim提供的详细答案。我正在开发一个插件应用程序,目标是在多个领域使用。我也想使用Facebook身份验证,但Facebook只支持来自单个域的身份验证。我想我可以采取你的方法,调整它,使弹出窗口总是去一个单一的域,这是由Facebook祝福。然后在身份验证之后,我可以向调用页面提供身份验证结果。再次感谢您对我的解释。我现在采用的方法是在不同的域中弹出一个窗口,这样我就可以使用facebook身份验证了。对于给定的Facebook应用程序,您只能让它与单个域一起工作(您可以使用子域等)。我的应用程序将嵌入许多客户端应用程序中(希望如此),因此,由于不同的域问题,我使用facebook有点受阻。我可以按照您的方法打开弹出窗口,但似乎无法调用回调函数将数据发送回调用方页面。我只能假设这是一个跨域问题。思想?感谢.+1提供简化的
    外部调用
    。我只接受我的应用程序的Facebook登录——没有本地凭据、twitter等——因此不需要用户名确认阶段,包括额外的重定向。谢谢
    
    [HttpGet]
    public ActionResult LoginPartial()
    {
        if (Request.IsAjaxRequest())
        {
            return View("_LoginPartial");
        }
    
        return new EmptyResult();
    }
    
    @{
        Layout = null;
    }