Аутентификация токена OWIN 400 Неправильный запрос на опции из браузера

Я использую токен аутентификации для небольшого проекта на основе этой статьи: http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/

Кажется, все работает нормально, за исключением одного: аутентификация токена на основе OWIN не разрешает запрос 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 ответов

Решение

Решил это. Проблема не была отправлена ​​с заголовком запроса OPTIONS Access-Control-Request-Method

Я потерял немного времени на эту проблему сегодня. Наконец я думаю, что нашел решение.

Переопределите метод внутри вашего 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);
}

Это делает три необходимые вещи:

  • Принудительно заставить сервер аутентификации отвечать на запрос OPTIONS с HTTP-статусом 200 (OK),
  • Разрешить отправку запроса из любой точки мира Access-Control-Allow-Origin
  • Позволяет Authorization заголовок, который будет установлен на последующие запросы путем установки Access-Control-Allow-Headers

После этих шагов angular, наконец, ведет себя корректно при запросе конечной точки токена методом OPTIONS. Статус OK возвращается и повторяет запрос методом POST для получения полных данных токена.

Переопределите этот метод внутри вашего OAuthAuthorizationServerProvider:

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

Вы запускаете его локально или публикуете в Azure, как в примере кода в статье блога?

Если вы используете его в Azure, вы можете легко исправить проблемы с CORS, включив CORS на портале Azure:

  1. Нажмите на службу приложений на портале Azure, чтобы открыть экран управления.
  2. В списке параметров управления прокрутите вниз до раздела "API", где вы найдете параметр "CORS". (В качестве альтернативы введите "CORS" в поле поиска).
  3. Введите разрешенный источник или введите "*", чтобы включить все, и нажмите "Сохранить".

Это устранило для меня проблему проверки перед полётом OPTIONS, которую некоторые другие люди, судя по всему, видели в коде этой статьи в блоге.

Это должно сделать трюк:

app.UseCors(CorsOptions.AllowAll);
Другие вопросы по тегам