OWIN令牌认证400来自浏览器的OPTIONS请求错误

时间:2014-10-28 17:31:13

标签: asp.net angularjs owin asp.net-web-api2

我正在根据这篇文章对小项目使用令牌身份验证:http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/

除了一件事之外,一切似乎都运行良好:基于OWIN的令牌认证不允许/ token端点上的OPTIONS请求。 Web API返回400 Bad Request,整个浏览器应用程序停止发送POST请求以获取令牌。

我在应用程序中启用了所有CORS,如示例项目中所示。下面是一些可能相关的代码:

public class Startup
    {
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

        public void Configuration(IAppBuilder app)
        {
            AreaRegistration.RegisterAllAreas();
            UnityConfig.RegisterComponents();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            HttpConfiguration config = new HttpConfiguration();

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            ConfigureOAuth(app);

            WebApiConfig.Register(config);

            app.UseWebApi(config);

            Database.SetInitializer(new ApplicationContext.Initializer());
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            //use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
                Provider = new SimpleAuthorizationServerProvider(),
                RefreshTokenProvider = new SimpleRefreshTokenProvider()
            };

            // Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        }
    }

以下是我的javascript登录功能(我为此目的使用angularjs)

var _login = function (loginData) {

        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;

        data = data + "&client_id=" + ngAuthSettings.clientId;

        var deferred = $q.defer();

        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {

        localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName, refreshToken: response.refresh_token, useRefreshTokens: true });
        _authentication.isAuth = true;
        _authentication.userName = loginData.userName;
        _authentication.useRefreshTokens = loginData.useRefreshTokens;

        deferred.resolve(response);

        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });

        return deferred.promise;
    };

    var _logOut = function () {

        localStorageService.remove('authorizationData');

        _authentication.isAuth = false;
        _authentication.userName = "";
        _authentication.useRefreshTokens = false;

    };

5 个答案:

答案 0 :(得分:34)

我今天在这个问题上已经失去了一些时间。最后我想我找到了解决方案。

覆盖OAuthAuthorizationServerProvider中的方法:

public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
    if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization" });
        context.RequestCompleted();
        return Task.FromResult(0);
    }

    return base.MatchEndpoint(context);
}

这似乎做了三件必要的事情:

  • 强制auth服务器以200(OK)HTTP状态
  • 响应OPTIONS请求
  • 通过设置Access-Control-Allow-Origin
  • ,允许来自任何地方的请求
  • 通过设置Authorization
  • ,允许在后续请求中设置Access-Control-Allow-Headers标头

在这些步骤之后,当使用OPTIONS方法请求令牌端点时,angular最终表现正确。返回OK状态,并使用POST方法重复请求以获取完整的令牌数据。

答案 1 :(得分:1)

OAuthAuthorizationServerProvider

中覆盖此方法
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

答案 2 :(得分:0)

您是在本地运行它,还是像博客文章的示例代码中那样将其发布到Azure?

如果在Azure上运行它,则可以通过在Azure门户中启用CORS来轻松解决CORS问题:

  1. 在Azure门户中单击您的应用程序服务以进入管理屏幕。
  2. 在管理选项列表中,向下滚动到“ API”部分,您将在其中找到“ CORS”选项。 (或者在搜索框中输入“ CORS”。)
  3. 输入允许的来源,或输入“ *”以启用所有功能,然后单击“保存”。

这为我解决了OPTIONS飞行前检查问题,其他人似乎从该特定博客文章中的代码中得到了解决。

答案 3 :(得分:-3)

解决了它。问题是没有使用OPTIONS请求标头Access-Control-Request-Method

发送

答案 4 :(得分:-4)

这应该可以解决问题:

app.UseCors(CorsOptions.AllowAll);