2016-03-29 80 views
11

我有一个Angular2应用程序。它在ASP.NET 5(Core)中运行。
它使Http调用正在工作正常的控制器。Angular2 ASP.NET Core AntiForgeryToken

但现在我需要建立跨站点脚本投影。

如何在每个Http请求上生成新令牌,然后在Angular2应用中执行AntiForgeryToken检查?

注意:我在Angular中的数据表单不是从MVC视图生成的,而是完全用Angular2编写的,只能调用Web服务。

我所看到的所有例子都过时了,不起作用/不能完全工作。

如何整合AntiForgeryToken检查Angular2针对ASP.NET 5,其中窗体是纯的Angular?

感谢。

回答

6

自定义操作筛选器不是必需的。它可以在Startup.cs中全部连线。

using Microsoft.AspNetCore.Antiforgery; 

(...) 

public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); 

    (...) 
} 

public void Configure(IApplicationBuilder app, IAntiforgery antiforgery) 
{ 
    app.Use(next => context => 
    { 
    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 }); 
    } 
    return next(context); 
    }); 

    (...) 
} 

然后你在你的控制器需要的是[ValidateAntiForgeryToken]装饰,无论你想执行一个令牌提供。

作为参考,我在这里找到了这个解决方案 - AspNet AntiForgery Github Issue 29

+0

我遵循上述步骤,但我得到400错误的请求错误。我的“发布”请求发送到服务器作为“选项:方法类型。我问了一个关于这个问题的问题 - https://stackoverflow.com/questions/44841588/antiforgery-token-implementation-in-angular-2-and- web-api-using-aps-net-core –

+0

我今天发现的一些其他信息 - 如果您在IIS中托管,则应在服务器上配置Data Protection以保留用于生成AntiForgeryToken的密钥。 ,应用程序重新启动时令牌将变为无效。有关如何配置的信息,请参阅此处 - https://docs.microsoft.com/en-us/aspnet/core/publishing/iis#data-protection – DanO

0

我想你需要制作自定义的AntiForgeryValidationToken属性,该属性支持通过头部而不是表单值发送令牌。然后将标记添加到您的Angular2应用程序到您的api的每个请求的标题中。这里How do you set global custom headers in Angular2?

0

例如从头验证令牌就可以使用这样的事情:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 
    public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter 
    { 
     public void OnAuthorization(AuthorizationContext filterContext) 
     { 
      if (filterContext == null) 
      { 
       throw new ArgumentNullException(nameof(filterContext)); 
      } 

      var httpContext = filterContext.HttpContext; 
      if (httpContext.Request.Headers["__RequestVerificationToken"] == null) 
      { 
       httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; 
       httpContext.Response.StatusDescription = "RequestVerificationToken missing."; 

       filterContext.Result = new JsonResult 
       { 
        Data = new { ErrorMessage = httpContext.Response.StatusDescription }, 
        JsonRequestBehavior = JsonRequestBehavior.AllowGet 
       }; 
       return; 
      } 
      var cookie = httpContext.Request.Cookies[System.Web.Helpers.AntiForgeryConfig.CookieName]; 
      System.Web.Helpers.AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]); 
     } 
    } 

然后你只需要添加[ValidateHeaderAntiForgeryToken]在您的控制器的方法。请注意,这是来自MVC 5,ASP.NET 4.5.2项目,因此您可能需要稍微修改它以适应.NET Core。另外,我修改了这个以返回JSON结果(如果令牌缺失),如果不处理错误响应并将其输出给用户,则可以删除该部分。 学分此属性的核心部分去:https://nozzlegear.com/blog/send-and-validate-an-asp-net-antiforgerytoken-as-a-request-header

难的是如何产生AntiForgeryToken没有纯角2应用程序中使用@Html.AntiForgeryToken()(不访问.cshtml文件)。我也在寻找答案。

+0

我想知道你是否曾经发现过如何在不使用@ Html.AntiForgeryToken()的情况下创建标记的答案? – Jeremy

2

我正在使用操作筛选器来发送请求令牌。 只需将其应用于您想要新防伪令牌的操作,例如Angular2 SPA,的WebAPI动作等

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 
public class AngularAntiForgeryTokenAttribute : ActionFilterAttribute 
{ 
    private const string CookieName = "XSRF-TOKEN"; 
    private readonly IAntiforgery antiforgery; 

    public AngularAntiForgeryTokenAttribute(IAntiforgery antiforgery) 
    { 
     this.antiforgery = antiforgery; 
    } 

    public override void OnResultExecuting(ResultExecutingContext context) 
    { 
     base.OnResultExecuting(context); 

     if (!context.Cancel) 
     { 
      var tokens = antiforgery.GetAndStoreTokens(context.HttpContext); 

      context.HttpContext.Response.Cookies.Append(
       CookieName, 
       tokens.RequestToken, 
       new CookieOptions { HttpOnly = false }); 
     } 
    } 
} 
/* HomeController */ 

[ServiceFilter(typeof(AngularAntiForgeryTokenAttribute), IsReusable = true)] 
public IActionResult Index() 
{ 
    return View(); 
} 

/* AccountController */ 

[HttpPost()] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
// Send new antiforgery token 
[ServiceFilter(typeof(AngularAntiForgeryTokenAttribute), IsReusable = true)] 
public async Task<IActionResult> Register([FromBody] RegisterViewModel model) 
{ 
    //... 
    return Json(new { }); 
} 

注册在启动属性,并配置防伪服务读取请求令牌形式 “X-XSRF-TOKEN” 报头。

public class Startup 
{ 
    // ... 

    public void ConfigureServices(IServiceCollection services) 
    { 
     // ... 

     services.AddScoped<AngularAntiForgeryTokenAttribute>(); 
     services.AddAntiforgery(options => 
     { 
      options.HeaderName = "X-XSRF-TOKEN"; 
     }); 
    } 
} 
+0

有关如何在SPA中使用此方法的任何建议? GET行为实际上从来没有受到影响(除了/ Home/Index),您如何为每个将在稍后发布POST的表单提供新的标记? –

+1

尝试将AngularAntiForgeryTokenAttribute应用于您的POST端点。您应该可以在POST操作中更新令牌。 – fszlin