简体   繁体   English

Angular 8 + Jwt + [授权] + DotNet Core 2.1 Api + Chrome 发布请求失败,并出现 Z727183C8F28CA 错误

[英]Angular 8 + Jwt + [Authorize] + DotNet Core 2.1 Api + Chrome post request fails with cors error

I know this is a very common problem I faced myself in the past, but I was always able to deal with it enabling cors in DotNet Core Api startup.cs, but what's going on this time seems a little bit more weird.我知道这是我过去遇到的一个非常常见的问题,但是我总是能够在 DotNet Core Api startup.cs 中启用 cors 来处理它,但是这次发生的事情似乎有点奇怪。

My Angular 8 app does a post request first at login (this request inlcudes no httpHeader because no token is present yet) and it works (I have previously enabled cors for it to work).我的 Angular 8 应用程序在登录时首先发出一个 post 请求(此请求不包含 httpHeader,因为还没有令牌)并且它可以工作(我之前已启用 cors 以使其工作)。

After I get a token I store it in localstorage for later use, but to my big surprise when api controller has [Authorize] tag and the post includes header with token, then request fails with cors error and it doesn't even hit server method. After I get a token I store it in localstorage for later use, but to my big surprise when api controller has [Authorize] tag and the post includes header with token, then request fails with cors error and it doesn't even hit server method .

Error in vscode console: 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/]

Angular 8 post request that works (login) and I got return (token): Angular 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;
        }));
}

Authenticate method in login controller that works:登录 controller 中的验证方法有效:

[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 });
}

Angular 8 post request that fails: Angular 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;
    }));

Angular 8 post request that also fails: Angular 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 Core Api controller method that is not even get hit: DotNet Core Api controller 方法甚至没有被击中:

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

startup.cs "ConfigureServices" method where I enable cors:我启用 cors 的 startup.cs“ConfigureServices”方法:

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));
}

The weird thing is if I remove [Authorize] directive from "Add" method then it works, but I obviously lose token validation.奇怪的是,如果我从“添加”方法中删除 [Authorize] 指令,那么它会起作用,但我显然会丢失令牌验证。

Help, please:)请帮忙:)

After hours of struggling my head I figured out:经过几个小时的努力,我发现:

First I forgot to use首先我忘了使用

app.UseAuthentication();

in Configure in startup.cs在startup.cs中配置

Second, instead of just其次,不仅仅是

[Authorize]

I have to use我必须使用

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

to define a default validation schema.定义默认验证模式。

Third I didn't know I have to install第三我不知道我必须安装

"AspNet.Security.OAuth.Validation"

to implement token validation.实现令牌验证。 Did it through Nuget manager.通过 Nuget 管理器完成。

Now it works, so I answer my own question, and I hope this will help anyone else with the same problem.现在它起作用了,所以我回答了我自己的问题,我希望这能帮助其他有同样问题的人。

Edit 1: To avoid "401 Unauthorized" error.编辑1:为了避免“401 Unauthorized”错误。

With all mentioned steps above I got controller method to start being hit, but the response was always being 401 (even with a valid token), so I had to add the next piece of code in startup to make it to validate correctly:通过上面提到的所有步骤,我得到了 controller 方法开始被击中,但响应始终是 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"
                    };
                });

I know there are obviously many different ways to achieve this, but this combination of pieces of code worked in my case for a basic use of case.我知道显然有很多不同的方法可以实现这一点,但是这种代码片段的组合在我的案例中适用于案例的基本使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM