Получение токена из веб-API2 из Angular2 приводит к проблемам с CORS или нулю - PullRequest
0 голосов
/ 06 июля 2018

Я пытаюсь выполнить вход (Angular2 - клиент и веб-API 2 - на сервере).

Я получаю

ОПЦИИ http://localhost:48604/Token 400 (неверный запрос)

с последующим

Не удалось загрузить http://localhost:48604/Token: Ответ на запрос предварительной проверки не проходит проверку контроля доступа: в запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Происхождение 'http://localhost:4200' поэтому не разрешено. Ответ имеет HTTP-код состояния 400.

, в то время как другие запросы не срабатывают из-за проблемы CORS, потому что у меня CORS включен глобально в WebApiConfig.cs :

Веб-API:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
        EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
        config.EnableCors(cors);
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );


    }
}

My Startup.Auth.cs :

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        // ... Code for third-part logins omitted for brevity ...
    }
}

Мой угловой сервис:

export class AuthService {

rootUrl = 'http://localhost:48604';

httpOptions = {
    headers: new HttpHeaders({
        'Content-Type': 'application/x-www-form-urlencoded'
    })
};

constructor(private httpClient: HttpClient) {
}

logIn(loginData): Observable<any> {

    const data = 'grant_type=password&username=' + loginData.username + '&password=' + loginData.password;
    return this.httpClient.post(this.rootUrl + '/Token', data, this.httpOptions);
}
}

И, насколько я понимаю, после / Token запрос должен быть перенаправлен на api / Account / ExternalLogin , но никогда не попадает в этот метод контроллера.

Затем я нашел сообщение , где они говорят, что вам нужно переопределить MatchEndpoint метод в ApplicationOAuthProvider классе, и я сделал это:

        public override Task MatchEndpoint(OAuthMatchEndpointContext context)
    {
        if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" });
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization"});
            context.RequestCompleted();

            return Task.FromResult(0);
        }

        return base.MatchEndpoint(context);
    }

в моем компоненте входа:

    this.authService.logIn(loginData).subscribe(
  (data) => {
    console.log(data);
    //sessionStorage.setItem('tokenKey', token);
    //console.log('sessionStorage.getItem: ' + sessionStorage.getItem('tokenKey'));
  },

);

теперь я отвечаю на запрос POST 200 OK, но консоль все еще говорит:

Не удалось загрузить http://localhost:48604/Token: Нет заголовка «Access-Control-Allow-Origin» на запрошенном ресурсе. Origin 'http://localhost:4200' поэтому не допускается.

затем я добавляю еще один, если для метода POST, где я также добавляю необходимые заголовки:

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

        if (context.IsTokenEndpoint && context.Request.Method == "POST")
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" });
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization", "Content-Type" });
            context.RequestCompleted();
            return Task.FromResult(0);
        }
        return base.MatchEndpoint(context);
    }

Теперь метод POST будет добавлять заголовки к ответу. но вместо токена я получаю ноль.

Ответы [ 2 ]

0 голосов
/ 08 июля 2018

Хорошо. Задача решена. Как объяснено в этом видео (31:00 минута)

Таким образом, ASP.NET Identity использует OWIN, и ему необходимо включить CORS в ConfigureAuth метод Startup.cs файла

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {

        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
        app.UseCors(CorsOptions.AllowAll);
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        // ... Code for third-part logins omitted for brevity ...
    }
}

Теперь для этого нам нужно установить пакет nuget в проект:

Install-Package Microsoft.Owin.Cors

И мне больше не нужно включать CORS в файле WebApiConfig:

EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(cors);

Файл WebApiConfig

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
       // EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
        // config.EnableCors(cors);
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );


    }
}

Мне также не нужно переопределять метод MatchEndpoint, как я писал ранее.

Теперь, когда я делаю запрос на вход, я получаю ответ с токеном:

Request URL: http://localhost:48604/Token

и я вижу, в ответ добавляются заголовки:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4200

Когда я отправляю запрос другому контроллеру API, скажите:

Request URL: http://localhost:48604/api/UpdateUsrRole

Сначала я вижу это в методе запроса: ОПЦИИ добавлены следующие заголовки:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Origin: http://localhost:4200

и затем, когда срабатывает метод запроса: PUT добавлены следующие заголовки:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4200

Вот и все.

0 голосов
/ 06 июля 2018

Вы можете добавить файл proxy.config.json в ваше угловое приложение, чтобы разрешить CORS, так как Angular работает на порте 4200 и ваш бэкэнд, вероятно, что-то еще.

https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md

затем подайте через ng serve --proxy-config proxy.config.json

Это перезапишет любые запросы на указанный порт и т. Д. (Ваш бэкэнд)

Если вы собираете свое приложение все в одном пакете, у вас не должно быть проблемы с cors. ** Создание угловых и добавление статических ресурсов для бэкэнда **

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...