Merge pull request #3671 from sbwalker/dev

fix #3669 add CORS policy and use Jwt with XHR to allow file uploads to work in .NET MAUI
This commit is contained in:
Shaun Walker 2024-01-23 10:34:39 -05:00 committed by GitHub
commit 0387bde81b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 32 additions and 6 deletions

View File

@ -4,6 +4,7 @@
@inject IFolderService FolderService @inject IFolderService FolderService
@inject IFileService FileService @inject IFileService FileService
@inject ISettingService SettingService @inject ISettingService SettingService
@inject IUserService UserService
@inject IStringLocalizer<FileManager> Localizer @inject IStringLocalizer<FileManager> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer @inject IStringLocalizer<SharedResources> SharedLocalizer
@ -370,7 +371,12 @@
// upload the files // upload the files
var posturl = Utilities.TenantUrl(PageState.Alias, "/api/file/upload"); var posturl = Utilities.TenantUrl(PageState.Alias, "/api/file/upload");
var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString(); var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString();
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken); var jwt = "";
if (PageState.Runtime == Shared.Runtime.Hybrid)
{
jwt = await UserService.GetTokenAsync();
}
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt);
// uploading is asynchronous so we need to poll to determine if uploads are completed // uploading is asynchronous so we need to poll to determine if uploads are completed
var success = true; var success = true;

View File

@ -198,13 +198,13 @@ namespace Oqtane.UI
} }
} }
public Task UploadFiles(string posturl, string folder, string id, string antiforgerytoken) public Task UploadFiles(string posturl, string folder, string id, string antiforgerytoken, string jwt)
{ {
try try
{ {
_jsRuntime.InvokeVoidAsync( _jsRuntime.InvokeVoidAsync(
"Oqtane.Interop.uploadFiles", "Oqtane.Interop.uploadFiles",
posturl, folder, id, antiforgerytoken); posturl, folder, id, antiforgerytoken, jwt);
return Task.CompletedTask; return Task.CompletedTask;
} }
catch catch

View File

@ -284,7 +284,7 @@ Oqtane.Interop = {
} }
return files; return files;
}, },
uploadFiles: function (posturl, folder, id, antiforgerytoken) { uploadFiles: function (posturl, folder, id, antiforgerytoken, jwt) {
var fileinput = document.getElementById('FileInput_' + id); var fileinput = document.getElementById('FileInput_' + id);
var files = fileinput.files; var files = fileinput.files;
var progressinfo = document.getElementById('ProgressInfo_' + id); var progressinfo = document.getElementById('ProgressInfo_' + id);
@ -323,6 +323,10 @@ Oqtane.Interop = {
data.append('formfile', Chunk, FileName); data.append('formfile', Chunk, FileName);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', posturl, true); request.open('POST', posturl, true);
if (jwt !== "") {
request.setRequestHeader('Authorization', 'Bearer ' + jwt);
request.withCredentials = true;
}
request.upload.onloadstart = function (e) { request.upload.onloadstart = function (e) {
if (progressinfo !== null && progressbar !== null) { if (progressinfo !== null && progressbar !== null) {
progressinfo.innerHTML = file.name + ' 0%'; progressinfo.innerHTML = file.name + ' 0%';

View File

@ -131,6 +131,16 @@ namespace Oqtane
.WithSiteIdentity() .WithSiteIdentity()
.WithSiteAuthentication(); .WithSiteAuthentication();
services.AddCors(options =>
{
options.AddPolicy(Constants.MauiUserAgent,
policy =>
{
policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0")
.AllowAnyHeader().AllowCredentials();
});
});
services.AddMvc(options => services.AddMvc(options =>
{ {
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
@ -176,6 +186,7 @@ namespace Oqtane
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseCors(Constants.MauiUserAgent);
app.UseTenantResolution(); app.UseTenantResolution();
app.UseJwtAuthorization(); app.UseJwtAuthorization();
app.UseBlazorFrameworkFiles(); app.UseBlazorFrameworkFiles();

View File

@ -284,7 +284,7 @@ Oqtane.Interop = {
} }
return files; return files;
}, },
uploadFiles: function (posturl, folder, id, antiforgerytoken) { uploadFiles: function (posturl, folder, id, antiforgerytoken, jwt) {
var fileinput = document.getElementById('FileInput_' + id); var fileinput = document.getElementById('FileInput_' + id);
var files = fileinput.files; var files = fileinput.files;
var progressinfo = document.getElementById('ProgressInfo_' + id); var progressinfo = document.getElementById('ProgressInfo_' + id);
@ -323,6 +323,10 @@ Oqtane.Interop = {
data.append('formfile', Chunk, FileName); data.append('formfile', Chunk, FileName);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', posturl, true); request.open('POST', posturl, true);
if (jwt !== "") {
request.setRequestHeader('Authorization', 'Bearer ' + jwt);
request.withCredentials = true;
}
request.upload.onloadstart = function (e) { request.upload.onloadstart = function (e) {
if (progressinfo !== null && progressbar !== null) { if (progressinfo !== null && progressbar !== null) {
progressinfo.innerHTML = file.name + ' 0%'; progressinfo.innerHTML = file.name + ' 0%';

View File

@ -80,6 +80,7 @@ namespace Oqtane.Shared
public static readonly string MauiUserAgent = "MAUI"; public static readonly string MauiUserAgent = "MAUI";
public static readonly string MauiAliasPath = "Alias-Path"; public static readonly string MauiAliasPath = "Alias-Path";
public static readonly string VisitorCookiePrefix = "APP_VISITOR_"; public static readonly string VisitorCookiePrefix = "APP_VISITOR_";
// Obsolete constants // Obsolete constants