AntiForgery Token implementation in Angular 2 and Web Api using Aps.Net Core

≯℡__Kan透↙ 提交于 2019-12-12 18:17:01

问题


I have separate frontend project in Angular 2 without using MVC and backend project is Web Api (Asp.Net Core) both are hosted on different domain. I implemented AntiForgery token functionality but it is not working.

Frontend project (UI)- http://localhost:8080/

Backend project (Web Api) - http://localhost:4823/

I am able to receive and send XSRF-Token cookie in every request but api gives 400 Bad Request error. I followed this link- Angular2 ASP.NET Core AntiForgeryToken

Startup.cs-

public void ConfigureServices(IServiceCollection services)
{
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
    services.AddCors(options =>
    {
        options.AddPolicy("AllowAllCorsPolicy",
        builder => builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .AllowCredentials());
     });
}


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, IAntiforgery antiforgery)
{
    app.Use(async (context, next) =>
      {
        if (context.Request.Path == "/")
           {
             //send the request token as a JavaScript-readable cookie, and Angular will use it by default
             var tokens = antiforgery.GetAndStoreTokens(context);
             context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
           }
       }
}

Controller code-

[EnableCors("AllowAllCorsPolicy")]
[ValidateAntiForgeryToken]
[Produces("application/json")]
[Route("api/Aoi")]
public class AoiController : Controller
{
 ...
}

Angular code-

let options = new RequestOptions({ headers: headers, withCredentials:true });
this._http.post(this.aoiUrl, bodydata, options)
       .map((res: Response) => {
          let data = res.json();
          return data;
})


回答1:


cookies can not be shared across cross domains. so even though your web api project is appending the XSRF-TOKEN to its context response, it is not available to your front-end application hosted in a separate domain. I saw some workarounds that used fixed cookie name in both applications by configuring the options for AddAntiforgery() service.




回答2:


I think you should be able to get this working by enabling CORS. For more info, see here - https://docs.microsoft.com/en-us/aspnet/core/security/cors




回答3:


Configure Antiforgery cookie like this:

service.AddAntiforgery(options =>
            {
                options.HeaderName = "X-XSRF-TOKEN";
                options.Cookie.Name = "XSRF-TOKEN";
                options.Cookie.HttpOnly = false;
                options.Cookie.Path = "/";
                options.Cookie.SameSite = SameSiteMode.None;
            });



回答4:


I too have been looking at this lately and have done some testing and have also found a work around. The work around isn't too bad and allows you to start your development closer to a deployment scenario over working with ports.

I have found that setting up and enabling CORS in a .Net Core Web Api app will not allow you to use the built-in AntiForgeryToken mechanism. The solution that I found was to use Nginx.

Simply download Nginx and place the executable and package in a location of your choice. I use C:\nginx.

In your location, you will need to edit the Nginx config file. (./conf/nginx.conf)

In the nginx.conf file, see that your server{} part looks similar to this:

server {
  listen: 80;
  listen: 443 ssl;
  server_name: localhost;

  #My UI Project
        location ^~ / {
            proxy_pass http://127.0.0.1:4200/;
            proxy_set_header Upgrade $http_upgrade;
            #proxy_set_header Connection 'upgrade';
            proxy_set_header Connection $http_connection;
            proxy_set_header Host $host;
            proxy_http_version 1.1;
            proxy_cache_bypass $http_upgrade;
        }

        location ^~ /sockjs-node/ {
            proxy_pass htts://127.0.0.1:4200;
            proxy_set_header Upgrade $http_upgrade;
            #proxy_set_header Connection 'upgrade';
            proxy_set_header Connection $http_connection;
            proxy_set_header Host $host;
            proxy_http_version 1.1;
            proxy_cache_bypass $http_upgrade;
        }

        #My API Project
        location ^~ /myapi/ {
            proxy_pass http://127.0.0.1:5000;
            proxy_set_header Upgrade $http_upgrade;
            #proxy_set_header Connection 'upgrade';
            proxy_set_header Connection $http_connection;
            proxy_set_header Host $host;
            proxy_http_version 1.1;
            proxy_cache_bypass $http_upgrade;
        }
}

Here I list my Angular UI project ("My UI") that I have running at the root of the web server (ei: http://localhost)

We then to list out the sockjs-node using the same url as our Angular project.

Last, I list my API project ("My Api") and in the location, I have added the /myapi/ path. My api project will then be accessible from http://localhost/myapi and my Angular project accessible from http://locahost. Now both are using the same domain.

Start up the nginx server when you are starting your development work and then start your api project and your Angular project as you normally would.

After all are running, you can navigate to your app at localhost and if you want to navigate to an endpoint in your Api project, you would go to something like http://localhost/myapi/api/values/1.

Also notice that I have commented out the line: proxy_set_header Connection 'upgrade'; in the nginx.conf locations and instead used: proxy_set_header Connection $http_connection;. You will need this in order to have data sent and working properly to non-GET endpoints.

Another thing to be cognizant of, from what I have found with this setup, when using the AntiforgeryToken, setting either if these in your startup.cs... options.Filters.Add<AutoValidateAntiforgeryTokenAttribute>(); or services.AddScoped<AutoValidateAntiforgeryTokenAttribute>(); and also using the [AutoValidateAntiforgeryToken] class level attribute does NOT seem to kick off any validation. I have to add the [ValidateAntiForgeryToken] attribute to methods where we want to run the Antiforgery validation. Perhaps someone can comment on that part.



来源:https://stackoverflow.com/questions/44841588/antiforgery-token-implementation-in-angular-2-and-web-api-using-aps-net-core

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!