.Net Core:使用 Ionic 前端验证防伪令牌
.Net Core: Validate Anti Forgery Token with Ionic front end
我四处寻找并找到了类似的解决方案,但没有一个与我正在做的完全匹配。
我们有一个带有 API 控制器的 .net 核心 MVC 网站,用于处理来自我们也在开发的离子移动应用程序的请求。
在大多数情况下,将 [ValidateAntiForgeryToken]
添加到 API 控制器操作即可。我已经完成了生成令牌、将其传递给 Ionic 并将其存储在请求 header 中以供验证的过程。
这是我用来获取和存储令牌的代码:
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 插件的 headers:
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
而不是 built-in 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]
属性,文件会被正确 posted。但是,我尝试过的任何事情都无法与包含的属性一起使用。
我认为这个问题与 Ionic 自动添加到 cookie 的验证令牌有关,并且 cookie 与来自 http 插件的请求一起传递。但是,XMLHttpRequest
不传递 cookie(并且不能这样做?)。
在过去的几天里,我已经阅读了很多关于这个主题的内容,但我承认这个验证对我来说仍然是一个黑匣子。 有没有办法只使用在 header 中传递的令牌来验证我的操作中的请求?
我 运行 陷入这个问题的原因是我需要上传一个文件,而我使用 http 插件无法做到这一点。有使用 Ionic 的 file-transfer
插件上传图片的解决方案,但它已被弃用,发行说明建议改用 XmlHttpRequest
。
我尝试过的其他东西:
- 我找到了 .net 标准的解决方案,它使用
System.Web.Helpers.AntiForgery
在服务器上进行自定义验证,但此命名空间不包含在 .net 核心中,我找不到等效项。
- 我尝试了很多不同的方法来 post 使用 http 插件的文件(因为它在验证防伪令牌时没有问题)。我尝试的所有操作都会导致动作被击中,但被 posted 的文件始终是
null
。使用http插件上传文件的解决方案也是可以接受的。
为什么我能够在这个问题上花费整整两天时间,但是当我 post 提出问题后,我就找到了答案?有时候我觉得网络大神都在逗我
事实证明,本机 http 插件有一个 uploadFile()
功能,我从未在其他任何地方看到过。以下是解决方案的作用:
- 使用
fileChooser
插件从 phone 的存储select 文件
- 使用
filePath
插件解析图像的本机文件系统路径。
- 使用
http.uploadFile()
代替http.post()
之所以可行,是因为如上所述,我能够在 http 插件的 header 中正确设置验证令牌以供控制器接受。
这是代码:
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)
);
我四处寻找并找到了类似的解决方案,但没有一个与我正在做的完全匹配。
我们有一个带有 API 控制器的 .net 核心 MVC 网站,用于处理来自我们也在开发的离子移动应用程序的请求。
在大多数情况下,将 [ValidateAntiForgeryToken]
添加到 API 控制器操作即可。我已经完成了生成令牌、将其传递给 Ionic 并将其存储在请求 header 中以供验证的过程。
这是我用来获取和存储令牌的代码:
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 插件的 headers:
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
而不是 built-in 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]
属性,文件会被正确 posted。但是,我尝试过的任何事情都无法与包含的属性一起使用。
我认为这个问题与 Ionic 自动添加到 cookie 的验证令牌有关,并且 cookie 与来自 http 插件的请求一起传递。但是,XMLHttpRequest
不传递 cookie(并且不能这样做?)。
在过去的几天里,我已经阅读了很多关于这个主题的内容,但我承认这个验证对我来说仍然是一个黑匣子。 有没有办法只使用在 header 中传递的令牌来验证我的操作中的请求?
我 运行 陷入这个问题的原因是我需要上传一个文件,而我使用 http 插件无法做到这一点。有使用 Ionic 的 file-transfer
插件上传图片的解决方案,但它已被弃用,发行说明建议改用 XmlHttpRequest
。
我尝试过的其他东西:
- 我找到了 .net 标准的解决方案,它使用
System.Web.Helpers.AntiForgery
在服务器上进行自定义验证,但此命名空间不包含在 .net 核心中,我找不到等效项。 - 我尝试了很多不同的方法来 post 使用 http 插件的文件(因为它在验证防伪令牌时没有问题)。我尝试的所有操作都会导致动作被击中,但被 posted 的文件始终是
null
。使用http插件上传文件的解决方案也是可以接受的。
为什么我能够在这个问题上花费整整两天时间,但是当我 post 提出问题后,我就找到了答案?有时候我觉得网络大神都在逗我
事实证明,本机 http 插件有一个 uploadFile()
功能,我从未在其他任何地方看到过。以下是解决方案的作用:
- 使用
fileChooser
插件从 phone 的存储select 文件 - 使用
filePath
插件解析图像的本机文件系统路径。 - 使用
http.uploadFile()
代替http.post()
之所以可行,是因为如上所述,我能够在 http 插件的 header 中正确设置验证令牌以供控制器接受。
这是代码:
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)
);