简体   繁体   English

.Net Core:使用Ionic前端验证防伪令牌

[英].Net Core: Validate Anti Forgery Token with Ionic front end

I have looked all over and have found similar solutions, but nothing that matches exactly what I'm working on. 我四处张望,找到了类似的解决方案,但没有与我正在研究的完全匹配的解决方案。

We have a .net core MVC website with an API Controller for handling requests from an ionic mobile app which we are also developing. 我们拥有一个.net核心MVC网站,该网站带有API控制器,用于处理来自我们也在开发的离子移动应用程序的请求。

In most cases, adding [ValidateAntiForgeryToken] to the API controller actions works. 在大多数情况下,将[ValidateAntiForgeryToken]添加到API控制器操作即可。 I have gone through the process of generating the token, passing it to Ionic, and storing it in the request headers for validation. 我已经经历了生成令牌,将其传递给Ionic并将其存储在请求标头中进行验证的过程。

Here is the code I am using to fetch and store the token: 这是我用来获取和存储令牌的代码:

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 });
    }
}

Here is the action in my controller that serves anti forgery tokens: 这是控制器中提供防伪令牌的操作:

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

I set the headers of the http plugin by calling this function from the view's associated typescript file: 我通过从视图的关联打字稿文件中调用此函数来设置http插件的标头:

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

then any request I make with the http plugin is validated properly in the controller's action: 那么我通过http插件发出的任何请求都会在控制器的操作中得到正确验证:

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

Up to this point, everything works great. 到目前为止,一切正常。 The problem arises when I try to use XmlHttpRequest to for a POST instead of the built-in http plugin: 当我尝试使用XmlHttpRequest而不是内置的http插件进行POST时,就会出现问题:

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);

If I remove the [ValidateAntiForgeryToken] attribute from the controller's action, the file is posted properly. 如果我从控制器的操作中删除了[ValidateAntiForgeryToken]属性,则该文件将正确发布。 However, nothing I have tried has worked with the attribute being included. 但是,我没有尝试过使用包含的属性。

I believe the issue has something to do with the validation tokens being added to a cookie automatically by Ionic, and the cookie is passed along with the request from the http plugin. 我认为问题与Ionic自动将验证令牌添加到Cookie中有关,并且cookie与http插件的请求一起传递。 However, XMLHttpRequest does not pass the cookie along (and is unable to do so?). 但是, XMLHttpRequest不会传递cookie(并且不能传递cookie吗?)。

I have read up on the subject quite a bit over the past few days but I admit that this validation is still mostly a black box to me. 在过去的几天里,我已经阅读了很多有关该主题的文章,但我承认这种验证对我来说仍然是一个黑匣子。 Is there a way to validate the request in my action using only the token which is passed up in the header? 有没有一种方法可以仅使用在标头中传递的令牌来验证我的操作中的请求?

The reason I am running into this problem is that I need to upload a file, which I was unable to do using the http plugin. 我遇到此问题的原因是我需要上传一个文件,而我无法使用http插件执行该操作。 There are solutions for uploading images using Ionic's file-transfer plugin, but it has been deprecated and the release notes suggest using XmlHttpRequest instead. 有一些使用Ionic的file-transfer插件上传图像的解决方案,但已过时,建议使用XmlHttpRequest代替发行说明。

Other things I have tried: 我尝试过的其他方法:

  • I have found solutions for .net standard which use System.Web.Helpers.AntiForgery for custom validation on the server, but this namespace is not included in .net core and I could not find an equivalent. 我已经找到了使用System.Web.Helpers.AntiForgery在服务器上进行自定义验证的.net标准解决方案,但是该命名空间未包含在.net核心中,因此我找不到等效的名称空间。
  • I tried many different ways to post the file using the http plugin (since it has no issues validating the antiForgery token). 我尝试了多种使用http插件发布文件的方法(因为它没有验证antiForgery令牌的问题)。 Everything I tried resulted in the action being hit but the file being posted was always null . 我尝试的所有操作均导致操作被击中,但所发布的文件始终为null A solution which uploads a file using the http plugin would also be acceptable. 使用http插件上传文件的解决方案也是可以接受的。

Why is it that I was able to spend two full days on this problem, but as soon as I post a question about it, I find the answer? 为什么我可以在这个问题上花整整两天的时间,但是一旦发布问题,我就找到了答案? Sometimes I think the internet gods are just messing with me. 有时我认为互联网之神只是在惹我。

As it turns out, the native http plugin has an uploadFile() function that I never saw mentioned anywhere else. 事实证明,本机http插件具有一个uploadFile()函数,我在其他任何地方都没有提到过。 Here's what the solution does: 解决方案的作用如下:

  1. Use the fileChooser plugin to select a file from the phone's storage 使用fileChooser插件从手机的存储中选择一个文件
  2. Use the filePath plugin to resolve the native filesystem path of the image. 使用filePath插件解析图像的本机文件系统路径。
  3. Use http.uploadFile() instead of http.post() 使用http.uploadFile()代替http.post()

This works because as mentioned above, I was able to properly set the validation token in the http plugin's header to be accepted by the controller. 之所以如此,是因为如上所述,我能够在http插件的标头中正确设置验证令牌,以供控制器接受。

And here is the code: 这是代码:

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)
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Plaid:如何在前端(Ionic/angular)创建公共令牌并发送到服务器 - Plaid: how to create public token in the front end (Ionic/angular) and send to server 在ionic 4前端仅检索到部分响应 - Only part of the response is retrieved at the ionic 4 front-end 从ionic 2前端到php服务器的HTTP发布请求 - HTTP post request to a php server from ionic 2 front end 是否可以将Ionic用作前端,将node.js的npm库用作后端? - Is it possible to use Ionic as front-end and node.js's npm library as back-end? Ionic v2-如何知道前端何时完成渲染? - Ionic v2 - How to know when front-end finish rendering? 从离子/角度前端将json直接发布到Amazon s3存储桶 - post json directly to amazon s3 bucket from ionic/angular front end 我正在尝试将我的Azure后端与我的离子角度前端连接起来 - I am trying to connect my Azure backend with my ionic angular front end 使用ionic作为前端+ Devise-rails作为后端时的CSRF身份验证问题? - CSRF authentication issue when using ionic as front-end + Devise-rails as backend? 带有 .net 核心后端的 Ionic 使用电容器到 android 应用程序 - Ionic with .net core backend to android app using capacitor 使用Ionic来访问ASP.NET Core功能 - Using Ionic to access ASP.NET Core functionalities
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM