Angular2 ASP.NET Core AntiForgeryToken
У меня есть приложение Angular2. Он работает в ASP.NET 5 (Core).
Это делает Http-вызовы контроллеру, который работает нормально.
Но теперь мне нужно установить проекцию сценариев Cross Site.
Как создать новый токен для каждого запроса Http, а затем выполнить проверку AntiForgeryToken в Angular2 приложениях?
Примечание. Мои формы данных в Angular не создаются из представления MVC, но полностью написаны в Angular2 и вызывают только веб-службы.
Все примеры, которые я видел, устарели и не работают/не работают полностью.
Как интегрировать проверки AntiForgeryToken в Angular2 в ASP.NET 5, где формы являются чистыми Angular?
Спасибо.
Ответы
Ответ 1
Не требуется настраиваемый фильтр действий. Все это может быть подключено в 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.
Ответ 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 { });
}
Зарегистрируйте атрибут в Startup и настройте службу Antiforgery, чтобы прочитать заголовок маркера запроса "X-XSRF-TOKEN".
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<AngularAntiForgeryTokenAttribute>();
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
}
}
Ответ 3
Я думаю, вам нужно создать собственный атрибут AntiForgeryValidationToken, который поддерживает передачу токена через заголовок вместо значений формы. Затем добавьте токен в заголовок каждого запроса из вашего приложения Angular2 в ваш api. Пример здесь Как установить глобальные пользовательские заголовки в Angular2?
Ответ 4
Чтобы проверить токен из заголовка, вы можете использовать что-то вроде этого:
[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 без использования @Html.AntiForgeryToken()
в чистом приложении Angular 2 (без доступа к файлам .cshtml). Я также ищу ответ на этот вопрос.