【问题标题】:.Net Core: Validate Anti Forgery Token with Ionic front end.Net Core:使用 Ionic 前端验证防伪令牌
【发布时间】:2018-07-09 22:01:06
【问题描述】:

我已经到处寻找并找到了类似的解决方案,但没有一个完全符合我正在研究的解决方案。

我们有一个带有 API 控制器的 .net 核心 MVC 网站,用于处理来自我们也在开发的离子移动应用程序的请求。

在大多数情况下,将[ValidateAntiForgeryToken] 添加到 API 控制器操作是可行的。我已经完成了生成令牌、将其传递给 Ionic 并将其存储在请求标头中进行验证的过程。

这是我用来获取和存储令牌的代码:

static XSRF_TOKEN_KEY: string = "X-XSRF-TOKEN";
static XSRF_TOKEN_NAME_KEY: string = "X-XSRF-TOKEN-NAME";

constructor(){}

static getXsrfToken(http: HTTP) : {tokenName: string, token: string} {
    let tokenName: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);
    let token: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
    if(!tokenName || !token){
        this.fetchXsrfToken(http);
        tokenName= window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);
        token = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
    }
    return {
        tokenName: tokenName,
        token: token
    };
}

private static setXsrfToken({ token, tokenName }: { token: string, tokenName: string }) {
    window.sessionStorage.setItem(ValidationManager.XSRF_TOKEN_KEY, token);
    window.sessionStorage.setItem(ValidationManager.XSRF_TOKEN_NAME_KEY, tokenName);
}

private static fetchXsrfToken(http: HTTP) {
    let token: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
    let tokenName: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);

    if (!token || !tokenName) {
        let apiUrl: string = AppConfig.apiUrl + "/GetAntiforgeryToken";
        http.get(apiUrl, {}, {})
            .then(r => this.setXsrfToken(JSON.parse(r.data)))
            .catch(r => console.error("Could not fetch XSRFTOKEN", r));
    } else {
        this.setXsrfToken({ token: token, tokenName: tokenName });
    }
}

这是我的控制器中提供防伪令牌的操作:

[HttpGet]
public override IActionResult GetAntiforgeryToken()
{
    var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
    return new ObjectResult(new
    {
        token = tokens.RequestToken,
        tokenName = tokens.HeaderName
    });
    }

我通过从视图关联的打字稿文件中调用此函数来设置 http 插件的标头:

initializeHttp() {
    let token = ValidationManager.getXsrfToken(this.http);
    this.http.setHeader(token.tokenName, token.token);
    console.log("Http Initialized: ", token);
}

然后我使用 http 插件发出的任何请求都会在控制器的操作中得到正确验证:

this.http.post(apiUrl, {}, {}).then(response => {
   that.navCtrl.setRoot(HomePage);
});

到目前为止,一切正常。当我尝试使用XmlHttpRequest 来进行 POST 而不是内置的 http 插件时,就会出现问题:

let file = {
    name: e.srcElement.files[0].name,
    file: e.srcElement.files[0],
  };

  let formData: FormData = new FormData();
  formData.append('file', file.file);

  let xhr: XMLHttpRequest = new XMLHttpRequest();
  xhr.open('POST', apiUrl, true);
  console.log("setting request header: ", tokenVal); //verify that tokenVal is correct
  xhr.setRequestHeader("X-XSRF-TOKEN", tokenVal);
  xhr.send(formData);

如果我从控制器的操作中删除[ValidateAntiForgeryToken] 属性,则文件会正确发布。但是,我没有尝试过使用包含的属性。

我认为这个问题与由 Ionic 自动添加到 cookie 的验证令牌有关,并且 cookie 与来自 http 插件的请求一起传递。但是,XMLHttpRequest 不会传递 cookie(并且无法这样做?)。

在过去的几天里,我已经阅读了很多关于这个主题的内容,但我承认这个验证对我来说仍然是一个黑匣子。 有没有办法仅使用在标头中传递的令牌来验证我的操作中的请求?

我遇到这个问题的原因是我需要上传一个文件,而我使用 http 插件无法做到这一点。有使用 Ionic 的 file-transfer 插件上传图片的解决方案,但它已被弃用,发行说明建议改用 XmlHttpRequest

我尝试过的其他方法:

  • 我找到了 .net 标准的解决方案,它使用 System.Web.Helpers.AntiForgery 在服务器上进行自定义验证,但这个命名空间不包含在 .net 核心中,我找不到等效的。
  • 我尝试了许多不同的方法来使用 http 插件发布文件(因为它在验证 antiForgery 令牌时没有问题)。我尝试的所有操作都导致动作被击中,但发布的文件始终是null。使用 http 插件上传文件的解决方案也是可以接受的。

【问题讨论】:

    标签: ionic-framework asp.net-core xmlhttprequest antiforgerytoken


    【解决方案1】:

    为什么我能够在这个问题上花费整整两天的时间,但是我一发布关于它的问题,我就找到了答案?有时候我觉得网络大神就是在逗我。

    事实证明,原生 http 插件有一个 uploadFile() 函数,这是我在其他任何地方从未见过的。以下是解决方案的作用:

    1. 使用fileChooser插件从手机存储中选择一个文件
    2. 使用filePath 插件来解析图像的本机文件系统路径。
    3. 使用http.uploadFile() 代替http.post()

    之所以有效,是因为如上所述,我能够在 http 插件的标头中正确设置验证令牌以被控制器接受。

    这里是代码:

    let apiUrl: string = AppConfig.apiUrl + "/UploadImage/";
    this.fileChooser.open().then(
      uri => {
        this.filePath.resolveNativePath(uri).then(resolvedPath => {
          loader.present();
          this.http.uploadFile(apiUrl,{ },{ },resolvedPath, "image")
          .then(result => {
            loader.dismiss();
            toastOptions.message = "File uploaded successfully!";
            let toast = this.toastCtrl.create(toastOptions);
            toast.present();
            let json = JSON.parse(result.data);
            this.event.imageUrl = json.imgUrl;
          })
          .catch(err => {
            console.log("error: ", err);
            loader.dismiss();
            toastOptions.message = "Error uploading file";
            let toast = this.toastCtrl.create(toastOptions);
            toast.present();
          });
        });
      }
    ).catch(
      e => console.log(e)
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-09
      • 2014-01-23
      • 1970-01-01
      • 2012-01-22
      • 2020-08-18
      • 2021-06-27
      • 2022-08-16
      • 1970-01-01
      相关资源
      最近更新 更多