使用Angular 4和Asp.Net Core 2获取ValidateAntiForgeryToken

ton*_*one 5 antiforgerytoken asp.net-identity asp.net-core angular

我目前正在尝试使安全性与新发布的Asp.Net Core 2.0上的Angular 4(4.3.5)配合使用,尤其是防伪令牌。

我正在使用JavascriptServices,它提供了入门应用程序(它是Visual Studio 2017.3中的默认Angular模板)。Javascript服务在.cshtml页面上托管Angular站点的主页。实际上,这确实是非常有益的,因为我可以使用标准表单身份验证(点网核心身份)将所有内容锁定下来,当用户不在时,将用户重定向到/ Account / Login上的单独(非Angular)登录页面。登录。然后您可以登录该页面并重定向到主页,然后在授权用户的上下文中启动并运行该spa。

该工作应用程序可以在这里找到。

最后一个难题是使ValidateAntiForgeryToken属性正常工作。当您登录到“帐户/登录”页面时,这很好,因为它不是在angular 4的上下文中运行。但是,当我在主页的Angular 4中运行时,当我向服务器发帖时,如果该属性存在,则该帖子将被ValidateAntiForgeryToken阻止。

因此,我已在Account / Logout方法上注释了ValidateAntiForgeryToken属性。这是因为我正在使用Angular http帖子从站点注销。在不使用该属性时可以使用,但是在使用该属性时会失败/被阻止。

继角4机制的文档,发现在这里,我已经改变了反伪造令牌名称以匹配角4识别。为此,我修改了Startup.cs文件,并添加了以下几行:

public void ConfigureServices(IServiceCollection services)
{
            services.AddAntiforgery(options =>
            {
                options.Cookie.Name = "XSRF-TOKEN";
                options.Cookie.HttpOnly = false;
            });
...
}
Run Code Online (Sandbox Code Playgroud)

这应该使Angular应用程序能够使用Angular 4期望的名称访问Anti Forgery cookie。

在我的应用程序中,我刚刚转换为使用新的HttpClient服务(显然,不推荐使用Http服务!)应该使用拦截器将XSRF_TOKEN自动发送到服务器。

但是我一直无法完成这项工作。

我尝试使用HttpClient服务进行标准的帖子通话:

this.httpClient.post(this.baseUrl + 'Account/Logout', "", options).subscribe(result => {
    location.replace("/");
}, error => {
    console.error(error);
})
Run Code Online (Sandbox Code Playgroud)

我尝试手动添加标题:

let token = this.cookieService.get("XSRF-TOKEN");
console.log(token);

var httpHeaders = new HttpHeaders({ 'XSRF-TOKEN': token })

this.httpClient.post(this.baseUrl + 'Account/Logout', "", { headers: httpHeaders }).subscribe(result => {
    location.replace("/");
}, error => {
    console.error(error);
})
Run Code Online (Sandbox Code Playgroud)

我尝试使用带有和不带有标题的旧服务:

let token = this.cookieService.get("XSRF-TOKEN");
        console.log(token);

        let headers = new Headers({
            //'Content-Type': 'application/json',
            'X-XSRF-TOKEN': token
        });
        let options = new RequestOptions({ headers: headers });
        this.http.post(this.baseUrl + 'Account/Logout', "", options).subscribe(result => {
            location.replace("/")
        }, error => console.error(error));
Run Code Online (Sandbox Code Playgroud)

不幸的是,我没有运气。还有其他人设法使它正常工作吗?

ton*_*one 1

好的,我已经找到解决方案了。

我的 Index.cshtml 页面现在如下所示:

@Html.AntiForgeryToken()

<app>Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}
Run Code Online (Sandbox Code Playgroud)

其作用是在服务器端生成防伪令牌,并将其放置在页面上的隐藏输入字段中。当您查看页面源代码时,隐藏的输入字段如下所示:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8DaEnvKVNL9EhPVzHKQWhC-PeT4eNm_svdTEyGZje4WnH34sBfG_D_AphtPzBM1JEkQUHsSX1KWBivxAOtPsOvfMKs5N_dLn0Sr3xRG-N2s0oFaa3-yvG87qdzXYm1yBSYH7dlRiBu5It3wi2iYzWqyo4B1i_iRtmikz41gmuldze8VE72zVqmeHZav5rQiHkw" />
Run Code Online (Sandbox Code Playgroud)

在我的 Logout 方法中,我获取令牌并将其在标头中提交到服务器端控制器。标头名称为 RequestVerificationToken,不需要下划线。

Logout() {

    let token: any = $("input[name=__RequestVerificationToken]").val();
    if (token !== null) {
        var httpHeaders: any = new HttpHeaders({ 'RequestVerificationToken': token });

        this.httpClient.post("/Account/Logout", null, { headers: httpHeaders }).subscribe(() => {
            window.location.replace("/Account/Login");
        }, error => {
            console.log(error);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

在服务器端,AntiForgery 过滤器运行,将其与提交的值进行比较,如果是预期的值,将允许执行服务器端的 Account/Logout 方法。

服务器端方法如下所示:

//
// POST: /Account/Logout
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
  await _signInManager.SignOutAsync();
  return RedirectToAction(nameof(HomeController.Index), "Home");
}
Run Code Online (Sandbox Code Playgroud)

在Logout方法中放置一个断点将证明它执行了。

这里可能有一个陷阱。我不确定令牌是否会在每个请求时发生变化。我没有对此做过任何测试。如果是这样,则需要在每次请求后将新令牌添加到页面。

另外,我不需要修改默认 cookie 的行为。我不是用 Angular 4 的方式来做这件事。它纯粹是 ASP.Net 方法。即在Startup.cs文件中的ConfigureServices方法中,我已经注释掉了Cookie的更改:

public void ConfigureServices(IServiceCollection services)
        {
            //services.AddAntiforgery(options =>
            //{
            //    options.Cookie.Name = "XSRF-TOKEN";
            //    options.Cookie.HttpOnly = false;
            //});
Run Code Online (Sandbox Code Playgroud)

如果您认为您已经找到了更好的方法,请务必发布您的解决方案。