Angular 8 + Jwt + [Authorize] + DotNet Core 2.1 Api + Chrome пост-запрос завершается с ошибкой cors - PullRequest
0 голосов
/ 29 сентября 2019

Я знаю, что это очень распространенная проблема, с которой я сталкивался в прошлом, но мне всегда удавалось справиться с ней, включая Cors в DotNet Core Api startup.cs, но то, что происходит в этот раз, кажется немного более странным.

Мое приложение Angular 8 сначала отправляет запрос на вход при входе в систему (этот запрос не включает httpHeader, поскольку токена еще нет), и он работает (ранее я включил cors для его работы).

После получения токена я сохраняю его в localalstorage для дальнейшего использования, но, к моему большому удивлению, когда контроллер api имеет тег [Authorize] и сообщение содержит заголовок с токеном, запрос завершается ошибкой cors и даже не попадает на сервер.method.

Ошибка в консоли vscode:

Access to XMLHttpRequest at 'http://localhost:55909/api/manifest/add' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. [http://localhost:4200/]

Угловой 8-почтовый запрос, который работает (вход в систему), и я получил возврат (токен):

login(username: string, password: string) {
    return this.http.post<any>(`${environment.apiUrl}/api/login/authenticate`, { username, password })
        .pipe(map(user => {
            let oUser = new User();                
            oUser.username = user['name'];
            oUser.token = user['token'];
            localStorage.setItem('currentUser', JSON.stringify(oUser));
            let token = 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token;
            this.currentUserSubject.next(user);
            return user;
        }));
}

Метод аутентификациив контроллере входа, который работает:

[HttpPost]
[Route("authenticate")]
[EnableCors("Cors")]
public ActionResult Authenticate(LoginRequest login)
{
    if (!validCredentials(login)) return userUnauthorized();

    TokenGenerator.settings = settings;
    var token = TokenGenerator.GenerateTokenJwt(login.Username);
    user.Token = token;

    return new JsonResult(new User { Name = user.Name, Token = user.Token });
}

угловой 8-почтовый запрос, который завершается неудачно:

this.headers = new HttpHeaders({
    'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token,
    'Content-Type': 'application/json'
});

return this.http.post<any>(`${environment.apiUrl}/api/manifest/add`, { name, surname, seat, flight }, { headers: this.headers })
    .pipe(map(result => {
        return result;
    }));

угловой 8-почтовый запрос, который также не выполняется:

this.headers = new HttpHeaders({
    'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token,
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Headers': 'Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name',
    'Access-Control-Allow-Methods': 'POST,GET,PUT,PATCH,DELETE,OPTIONS'
});

return this.http.post<any>(`${environment.apiUrl}/api/manifest/add`, { name, surname, seat, flight }, { headers: this.headers })
    .pipe(map(result => {
        return result;
    }));

DotNet CorМетод контроллера Api, который даже не попал:

[Authorize]
[HttpPost]
[Route("add")]
[EnableCors("Cors")]
public ActionResult Add(Passenger passenger)
{
    Response response = repository.addPassenger(passenger);
    return new JsonResult(response);
}

startup.cs Метод «ConfigureServices», где я включаю cors:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpContextAccessor();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    // Add functionality to inject IOptions<T>
    services.AddOptions();

    // Add our Config object so it can be injected
    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

    services.AddCors(o => o.AddPolicy("Cors", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowCredentials()
               .AllowAnyHeader();
    }));

    //Add repository to scope
    services.AddScoped<UserRepository>();
    services.AddScoped<PassengerRepository>();

    //sql connection and context (with crypted pass)
    var connection = getConnectionString();
    services.AddDbContext<Context>(options => options.UseSqlServer(connection));
}

Странная вещь, если я удаляю [Authorize] директива из метода «Add», тогда она работает, но я, очевидно, теряю проверку токена.

Помогите, пожалуйста:)

1 Ответ

0 голосов
/ 29 сентября 2019

После нескольких часов борьбы за голову я понял:

Сначала я забыл использовать

app.UseAuthentication();

в Configure in startup.cs

Второй, а не просто

[Authorize]

Мне нужно использовать

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

для определения схемы проверки по умолчанию.

В-третьих, я не знал, что мне нужно установить

"AspNet.Security.OAuth.Validation"

для реализации проверки токена.Сделал это через диспетчер Nuget.

Теперь это работает, поэтому я отвечаю на свой вопрос, и я надеюсь, что это поможет кому-то еще с той же проблемой.

Редактировать 1: Избежать "401 Несанкционированный"error.

Со всеми вышеупомянутыми шагами я получил метод контроллера, чтобы начать попадание, но ответ всегда был 401 (даже с действительным токеном), поэтому мне пришлось добавить следующий фрагмент кода при запускедля правильной проверки:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("thisisasupersecuresecretkey")),
                        RequireSignedTokens = false,
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = "http://localhost:55909",
                        ValidAudience = "http://localhost:55909"
                    };
                });

Я знаю, что, очевидно, есть много разных способов добиться этого, но эта комбинация фрагментов кода работала в моем случае для базового использования кейса.

...