asp.net-mvc-3 - ASP.Net MVC 4的OAuthWebSecurity是否可以打开弹出窗口

标签 asp.net-mvc-3 asp.net-mvc-4 oauth-2.0 facebook-oauth oauth-provider

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

最佳答案

解决此问题有几个方面:

  • 打开一个弹出窗口以容纳身份验证序列。
  • 身份验证完成后关闭弹出窗口。
  • 处理身份验证失败。
  • 更新父页面以反射(reflect)用户已通过身份验证的事实。

  • 这是我以MVC4 Internet Application模板为起点来实现这些要求的方式:

    要在弹出窗口中启动身份验证序列(而不是重定向到新页面),您需要修改_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>
    

    在当前状态下,此代码可以正确启动弹出窗口并允许执行身份验证序列,但是弹出窗口保持打开状态,并且如果指定了重定向URL,则弹出窗口将显示此页面,而不是将父页面重定向到该URL。

    要在成功(或失败)的身份验证之后使弹出窗口关闭自身,需要修改处理身份验证回调的 Controller 操作方法,以使其返回包含关闭该弹出窗口的JavaScript的自定义 View 。正如我们将在下面看到的,该机制还可以用于实现上述目标[3]和[4]的解决方案。
    [AllowAnonymous]
    public ActionResult ExternalLoginCallback(string returnUrl)
    {
        var result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
    
        if (!result.IsSuccessful)
        {
            return View("LoginResult", new LoginResultViewModel(false, Url.Action("ExternalLoginFailure")));
        }
    
        if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
        {
            return View("LoginResult", new LoginResultViewModel(true, returnUrl));
        }
    
        OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, result.UserName);
        return View("LoginResult", new LoginResultViewModel(true, returnUrl));
    }
    

    此操作方法是原始项目模板随附的ExternalLoginCallback()方法的简化版本。与原始实现不同,此简化的示例不支持在创建新帐户时允许用户定义个性化用户名,也不允许将多个OAuth或OpenID帐户与单个MVC用户帐户关联。但是,通过扩展上述模式以合并原始模板的更复杂的逻辑,这些功能是可行的。

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

    这是Loginresult View 的标记:
    @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>
    

    上面的 View 接受LoginResultViewModel类型的模型,该模型反射(reflect)了完成的身份验证尝试的结果:
    public class LoginResultViewModel
    {
        public LoginResultViewModel(bool success, string returnUrl)
        {
            Success = success;
            ReturnUrl = returnUrl;
        }
    
        public bool Success { get; set; }
        public string ReturnUrl { get; set; }
    }
    

    使用上述所有元素后,就可以启动一个身份验证序列,该序列在弹出窗口中执行,该序列完成后会自动关闭。如果身份验证成功,则用户将在此时登录,并且使用返回URL启动该用户(如果通过对受[Authorize]属性保护的操作方法的请求触发而自动发生),则父页面将是重定向到最初请求的URL。

    但是,如果身份验证是由用户显式启动的(例如,通过访问登录页面),则父页面将不会重定向,因此可能需要进行部分页面更新以反射(reflect)用户现在已登录的事实。在MVC模板示例中,必须更新页面以显示用户名和Logout按钮,而不是LoginRegister按钮。

    这可以通过在布局 View 中定义一个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>
    

    上面的JavaScript对新的action方法进行AJAX调用,该方法呈现并返回现有的_LoginPartial View :
    [HttpGet]
    public ActionResult LoginPartial()
    {
        if (Request.IsAjaxRequest())
        {
            return View("_LoginPartial");
        }
    
        return new EmptyResult();
    }
    

    必须对原始项目模板进行最后的修改。必须将_LoginPartial View 修改为无需布局 View 即可呈现:
    @{
        Layout = null;
    }
    

    关于asp.net-mvc-3 - ASP.Net MVC 4的OAuthWebSecurity是否可以打开弹出窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12632458/

    相关文章:

    Angularjs ng-show 不适用于 Viewbag

    javascript - 如何在 html 中显示表示 XML 的字符串?

    azure - 使用 OAuth 2.0 从 Azure B2C AD 访问用户数据

    asp.net-mvc-3 - MVC 3 在哪里加密用户的密码?

    c# - 在Sql中执行插入命令并返回插入的Id

    jquery - json post 后无法重定向

    android - 如何使用 OAuth2.0 解决 socialauth-android(by 3pillarlabs)和 Google Accounts/Google+

    python - Flask-OAuthlib OAuth2 客户端报错: "Missing access credentials."

    c# - ASP.NET MVC4,将 View 映射到具有多种具体类型的枚举

    c# - CS0411 : The type arguments for method 'System.Web.Mvc.Html.EditorExtensions.EditorFor<>)' cannot be inferred from the usage