Asp.net mvc 4 MVC WebApi+;基本身份验证&x2B;跨域JSONP

Asp.net mvc 4 MVC WebApi+;基本身份验证&x2B;跨域JSONP,asp.net-mvc-4,asp.net-web-api,jsonp,basic-authentication,Asp.net Mvc 4,Asp.net Web Api,Jsonp,Basic Authentication,我试图创建一个基于MVC的站点,通过WebApi向本地页面和外部客户端提供一些服务,因此需要JSONP来避免同源策略错误。问题是该站点使用的是基本身份验证,正如我从这里的其他帖子中了解到的,它不能与JSONP一起使用。我尝试按照帖子中的建议,将user:pass插入URL,但这不起作用,服务器返回未经授权的代码。此外,我还尝试在不注入密码的情况下拨打电话,因为我可以在浏览器中输入用户名和密码:浏览器按预期要求我提供凭据,但由于某种原因,它们被拒绝,结果再次变成未经授权的代码。但是凭证是可以的,我

我试图创建一个基于MVC的站点,通过WebApi向本地页面和外部客户端提供一些服务,因此需要JSONP来避免同源策略错误。问题是该站点使用的是基本身份验证,正如我从这里的其他帖子中了解到的,它不能与JSONP一起使用。我尝试按照帖子中的建议,将user:pass插入URL,但这不起作用,服务器返回未经授权的代码。此外,我还尝试在不注入密码的情况下拨打电话,因为我可以在浏览器中输入用户名和密码:浏览器按预期要求我提供凭据,但由于某种原因,它们被拒绝,结果再次变成未经授权的代码。但是凭证是可以的,我可以通过从同一个域成功运行完全相同的代码来确认这一点。有人能告诉我我的代码出了什么问题吗

我的MVC WebApi控制器操作如下:

[BasicAuthorize(Roles = "administrator,customer,trial")]
public class TextApiController : ApiController
{
      // ...

    public SomeResult Get([FromUri] SomeParams p)
    {
          // some processing which returns a SomeResult object
          //...
    }
}
其中,BasicAuthorize属性是从中修改的I类,如下所示:

[AttributeUsageAttribute(AttributeTargets.Class |
    AttributeTargets.Method, Inherited = true,
    AllowMultiple = true)]
public sealed class BasicAuthorizeAttribute : AuthorizeAttribute
{
    static private string DecodeFrom64(string sEncodedData)
    {
        byte[] encodedDataAsBytes = Convert.FromBase64String(sEncodedData);
        return Encoding.ASCII.GetString(encodedDataAsBytes);
    }

    static private bool GetUserNameAndPassword(HttpActionContext context,
        out string sUserName,
        out string sPassword,
        out bool bCookieAuthorization)
    {
        bCookieAuthorization = false;
        bool bSuccess = false;
        sUserName = sPassword = "";
        IEnumerable<string> headerVals;

        if (context.Request.Headers.TryGetValues("Authorization", out headerVals))
        {
            try
            {
                string sAuthHeader = headerVals.First();
                string[] authHeaderTokens = sAuthHeader.Split();

                if (authHeaderTokens[0].Contains("Basic"))
                {
                    string sDecoded = DecodeFrom64(authHeaderTokens[1]);
                    string[] aPairMembers = sDecoded.Split(new[] { ':' });
                    sUserName = aPairMembers[0];
                    sPassword = aPairMembers[1];
                } 
                else
                {
                    if (authHeaderTokens.Length > 1)
                        sUserName = DecodeFrom64(authHeaderTokens[1]);
                    bCookieAuthorization = true;
                } 

                bSuccess = true;
            }
            catch
            {
                bSuccess = false;
            }
        } 

        return bSuccess;
    }

    static private bool Authenticate(HttpActionContext actionContext,
        out string sUserName)
    {
        bool bIsAuthenticated = false;
        string sPassword;
        bool bCookieAuthorization;

        if (GetUserNameAndPassword(actionContext,
            out sUserName, out sPassword, out bCookieAuthorization))
        {
            // if the header tells us we're using Basic auth then log the user in
            if (!bCookieAuthorization)
            {
                if (WebSecurity.Login(sUserName, sPassword, true))
                    bIsAuthenticated = true;
                else
                    WebSecurity.Logout();
            } 
            // else get authentication from web security
            else
            {
                if (WebSecurity.IsAuthenticated) bIsAuthenticated = true;
                sUserName = WebSecurity.CurrentUserName;
            } 
        } 
        else actionContext.Response =
            new HttpResponseMessage(HttpStatusCode.BadRequest);

        return bIsAuthenticated;
    }

    private bool IsAuthorized(string sUserName)
    {
        SimpleRoleProvider roles =
            (SimpleRoleProvider)System.Web.Security.Roles.Provider;
          string[] aRoles = Roles.Split(new[] {','});

        return (aRoles.Any(sRole => roles.IsUserInRole(sUserName, sRole)));
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        string sUserName;

        if (Authenticate(actionContext, out sUserName))
        {
            if (!IsAuthorized(sUserName))
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
        } 
        else
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        } 
    }
}
}

  • 在Global.asax.cs中,我调用这个类的两个方法

  • 在web.config中添加:

  • 我在MVC控制器中创建了一个简单的操作方法,返回一些JSON。我计划稍后用[Authorize]来修饰,一旦调用正确地放在客户端,我就可以测试身份验证(和授权,添加角色)

  • 在视图中,我调用我的方法如下:

  • var text=$(“#输入”).val();
    var json=“{'text':”+json.stringify(text)+“}”;
    $.ajax({
    url:“/Home/GetSomeJson”,
    数据类型:“json”,
    数据:json,
    键入:“获取”,
    发送前:函数(xhr){
    xhr.withCredentials=true;
    },
    跨域:是的,
    用户名:$(“#user”).val(),
    密码:$(“#密码”).val(),
    成功:ajaxSuccessHandler,
    错误:AjaxerHandler
    });
    
    然而,检查标题时,我看不到任何来源。另外,这是否是向MVC action/WebApi传递CORS调用凭据(当然在现实世界中是HTTPS)的正确方法?

    为什么不启用web api服务而不是使用JSONP呢。这是一篇很好的文章,解释了如何在Web API中启用CORS支持

    ...
    <form>
        <fieldset>
            <legend></legend>
            <ol>
                <li>
                    input text
                    <input type="text" id="input"/>
                </li>
                <li>
                    username
                    <input type="text" id="user"/>
                </li>
                <li>
                    password
                    <input type="password" id="password"/>
                </li>
                <li><a href="#" id="apip">API: JSONP</a></li>
            </ol>
        </fieldset>
    </form>
    <div id="result"></div>
    <script>
        function getAuthorizationHeader(username, password) {
            "use strict";
            var authType;
    
            if (password == "") {
                authType = "Cookie " + $.base64.encode(username);
            }
            else {
                var up = $.base64.encode(username + ":" + password);
                authType = "Basic " + up;
            };
            return authType;
        };
    
        function ajaxSuccessHandler(data) {
            "use strict";
            $("#result").text(data);
        };
    
        function ajaxErrHandler(jqXHR, textStatus, errorThrown) {
            "use strict";
            $("#result").text(errorThrown + " : " + textStatus);
        }
    
        $(function () {
            "use strict";
    
            $("#apip").click(function () {
                "use strict";
                var text = $("#input").val();
                $.ajax({
                    url: "https://somesiteurl.com/api/wordapi?Text=" + encodeURIComponent(text),
                    dataType: "jsonp",
                    type: "GET",
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("Authorization", getAuthorizationHeader($("#user").val(), $("#password").val()));
                    },
                    success: ajaxSuccessHandler,
                    error: ajaxErrHandler
                });
            });
        });
    </script>
    
    static public class CorsConfig { public static void RegisterCorsForWebApi(HttpConfiguration httpConfig) { WebApiCorsConfiguration corsConfig = new WebApiCorsConfiguration();

        // this adds the CorsMessageHandler to the HttpConfiguration’s 
        // MessageHandlers collection
        corsConfig.RegisterGlobal(httpConfig);
    
        corsConfig
            .ForResources("Products")
            .ForOrigins("http://hello.net")
            .AllowAll();
    }
    
    public static void RegisterCorsForMvc(MvcCorsConfiguration corsConfig)
    {
        corsConfig
            .ForResources("Products.GetProducts")
            .ForOrigins("http://hello.net")
            .AllowAll();
    }
    
    var text = $("#input").val(); var json = "{'text': " + JSON.stringify(text) + "}"; $.ajax({ url: "/Home/GetSomeJson", dataType: "json", data: json, type: "GET", beforeSend: function (xhr) { xhr.withCredentials = true; }, crossDomain: true, username: $("#user").val(), password: $("#password").val(), success: ajaxSuccessHandler, error: ajaxErrHandler });