I am trying to post a file object to my nuxt 3 api route
Problem is:
Data from client has my file object
Data from server returns empty object
Screenshot of the issue
Where did my file object go?
const handleImageUpload = async (evt: Event) => {
const target = evt.target as HTMLInputElement
if (target.files) {
const file = target.files[0]
const upload: iUpload = {
name: file.name,
type: file.type,
file
}
console.log("data from client", upload)
try {
const { data, error } = await useFetch(constants.imageUploadApiUrl, {
headers: { "Content-type": "application/json" },
method: 'POST',
body: upload
})
console.log("data from server", data.value)
} catch (error) {
console.log(error)
}
}
}
constants.imageUploadApiUrl (api route) has the following
import { getQuery, readBody } from "h3"
import { iUpload } from "~~/helpers/interfaces"
export default defineEventHandler(async (event) => {
try {
const query = getQuery(event)
const body = await readBody(event) as iUpload
return { body }
} catch (error: any) {
return { error: error.message }
}
})
iUpload interface is this
export interface iUpload {
name: string;
type: string;
file: File;
}
I eventually got it working. Meanwhile it's using supabase as it's backend (forgot to mention that).
But here are the changes I made.
#1 - I added a utility function to convert the file to base64 string
export const getBase64 = (file: File) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
#2 - I updated the handleImageUpload function like below. The only change being in the file key
const handleImageUpload = async (evt: Event) => {
const target = evt.target as HTMLInputElement
if (target.files) {
const fileObj = target.files[0]
const upload: iUpload = {
path: id(memberName(store.selected), '-'),
name: fileObj.name,
file: await getBase64(fileObj) as string, // <**=**
type: fileObj.type
}
console.log("data from client", upload)
try {
const { data, error } = await useFetch(constants.imageUploadApiUrl, {
headers: { "Content-type": "multipart/form-data" },
method: 'POST',
body: upload
})
console.log("data from server", data.value)
} catch (error) {
console.log(error)
}
}
}
#3 - Furthermore I updated the server route as follows:
export default defineEventHandler(async (event) => {
try {
const body = await readBody(event) as iUpload
const filePath = `${body.path}/${body.name}`
const res = await fetch(body.file)
const blob = await res.blob()
const response = await supabase.storage
.from("pictures")
.upload(filePath, blob, {
contentType: body.type,
upsert: true,
})
return {
data: response.data,
error: response.error?.message,
}
} catch (error: any) {
return { error: error.message }
}
})
#4 - Lastly I updated the policies on supabase storage bucket and storage object to the following:
supabase storage policy update
I want to make my form submission happen server-side in order to not expose my API key. I plan to do this with netlify functions however I don't know how that would look with Axios. I've looked for examples on how to do this but I don't seem to find any. Could some help me I'm stuck as to what to put inside my the Netlify function? If anyone has worked with these two programs and could provide a hand that would be helpful here is my javascript with my submission function.
var form = document.querySelector("#user_form");
let reqHeaders = {
headers: {
Authorization: "Bearer",
}
}
let url = ""
let reqData = {
records: [
{
fields: null
}
]
}
let formData = {
firstName: "",
lastName: "",
email: ""
}
function logData(id, dataObj, value) {
dataObj[id] = value;
console.log(value)
}
function formMessg (id) {
document.querySelector(id).style.display = "block";
setTimeout(function(){
document.querySelector(id).style.display = "none";
form.reset();
}, 2500)
}
form.addEventListener("submit", function (e) {
e.preventDefault();
let spam = document.getElementById('spam').value;
try {
for(const data in formData){
if(formData[data] === "" || spam.length !== 0){
const error = new Error();
error.notVaild = true;
throw error;
}
}
reqData.records[0].fields = formData;
console.log(reqData);
axios.post(url, reqData, reqHeaders).then((res) => {
formMessg ('.success-messg');
form.style.display = "none";
})
.catch ((err) => {
throw err;
});
} catch (err){
if (err.reponse){
formMessg ('.fail-messg');
} else if (err.request) {
formMessg ('.fail-messg');
} else if ("Notvalid") {
formMessg ('.fill-messg');
}else {
console.log(err);
}
}
});
i have below code i want to post data from angular to Asp.net MVC but in object its null. method was call but parameter was null any idea why ??
ANGULAR
var result = { SearchText: "PARK"};
this.httpClient.post(
'http://localhost:55063/Common/PostAddress',result
).subscribe((res: any[]) => {
console.log(res);
this.data = res;
});
MVC
public class CommonController : Controller
{
protected SCommon sCommon = null;
public async Task<ActionResult> PostAddress(RoleModel Id)
{
sCommon = new SCommon();
var User = await sCommon.GetAddress(Id.SearchText).ConfigureAwait(false);
return Json(User, JsonRequestBehavior.AllowGet);
}
}
public class RoleModel
{
public string SearchText { get; set; }
}
try adding header to your post and stringify your body
const httpOptions = {
headers: new HttpHeaders({
"Content-Type": "application/json"
})
};
var result = { SearchText: "PARK"};
const body = JSON.stringify(result);
this.httpClient.post('http://localhost:55063/Common/PostAddress',body,httpOptions).subscribe((res: any[]) => {
console.log(res);
this.data = res;
});
aslo enable cors like this in your Register method
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
I've seen similar threads to this issue, but I had no luck solving it.
LogIn worked successfuly but when I try to GET data of the user loggedIn in my home page I receive this error 401 Unauthorized the same erroe is showen also in Postman
My startup.cs
public class Startup
{
private string _connectionString=null;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//Inject AppSettings
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
_connectionString = Configuration["secretConnectionstring"];
//without this it will define for example id to Id
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options => {
var resolver = options.SerializerSettings.ContractResolver;
if (resolver != null)
(resolver as DefaultContractResolver).NamingStrategy = null;
});
services.AddEntityFrameworkNpgsql()
.AddDbContext<ApiContext>(
opt => opt.UseNpgsql(_connectionString));
services.AddEntityFrameworkNpgsql()
.AddDbContext<AuthentificationContext>(
options => options.UseNpgsql(_connectionString));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<AuthentificationContext>();
services.Configure<IdentityOptions>(options => {
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 4;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// Jwt Authentification
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x=> {
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
});
services.AddTransient<dataSeed>();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, dataSeed seed)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
// global policy - assign here or on each controller
app.UseCors("CorsPolicy");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
app.UseAuthentication();
}
}
}
UserprofileController
{
[Route("api/[controller]")]
[ApiController]
public class UserProfileController : ControllerBase
{
private UserManager<ApplicationUser> _userManager;
public UserProfileController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
[Authorize]
//GET : /api/UserProfile
public async Task<Object> GetUserProfile()
{
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _userManager.FindByIdAsync(userId);
return new
{
user.fullName,
user.Email,
user.UserName
};
}
}
}
UserServices
headers = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
}
readonly BaseUrl = 'http://localhost:53847/api';
constructor(private fb: FormBuilder, private http: HttpClient) { }
formModel = this.fb.group({
UserName: ['', Validators.required],
Email: ['', Validators.email],
fullName: ['', Validators.required],
Passwords: this.fb.group({
Password: ['',[Validators.required, Validators.minLength(4)]],
ConfirmPassword: ['', Validators.required],
}, { validator : this.comparePasswords})
});
comparePasswords(fb: FormGroup) {
let confirmPswdCtrl = fb.get('ConfirmPassword');
//passowrdMismatch
//confirmPswdCtrl.errors={passowrdMismatch:true}
if (confirmPswdCtrl.errors == null || 'passowrdMismatch' in confirmPswdCtrl.errors) {
if (fb.get('Password').value != confirmPswdCtrl.value)
confirmPswdCtrl.setErrors({ passowrdMismatch: true });
else
confirmPswdCtrl.setErrors(null);
}
}
register() {
var body = {
UserName: this.formModel.value.UserName,
Email: this.formModel.value.Email,
fullName: this.formModel.value.fullName,
Password: this.formModel.value.Passwords.Password,
};
return this.http.post(this.BaseUrl + '/ApplicationUser/Register', body, this.headers);
}
login(formData) {
return this.http.post(this.BaseUrl + '/ApplicationUser/Login', formData, this.headers);
}
getUserProfile() {
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
return this.http.get(this.BaseUrl + '/UserProfile', { headers: tokenHeader });
}
}
ApplicationUserController the PostMethod
[HttpPost]
[Route("Login")]
//POST : /api/ApplicationUser/Login
public async Task<IActionResult> Login(LoginModel model)
{
var user = await _userManager.FindByNameAsync(model.UserName);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("UserID",user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
else
return BadRequest(new { message = "Username or password is incorrect." });
}
}
Help Plz .. Thx
In my case I wasn't getting an error and everything appeared to work but my API returned 401 every time.
Having banged my head a lot on this.
I had ...
[Authorize]
on my Controller and found that the site was trying to use cookie authentication so although my JWT worked fine, the lack of a cookie auth made it fail.
I changed the attribute to ...
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
and this fixed the issue as now the controller ignores cookie auth and concentrates only on jwt.
Hope this helps someone
I found that changing the order of statements was my problem. Configure() requires ASP.NET Core middleware to be in the correct order.
This DID NOT work, and required me to add [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] to every controller...
app.UseAuthorization();
app.UseAuthentication();
This DOES work:
app.UseAuthentication();
app.UseAuthorization();
One problem I see is here:
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
When specifying a Bearer token, you need to leave a space between Bearer and the token itself, so that the result looks like this:
Authorization: <type> <credentials>
In your case, that would translate to:
Authorization: Bearer token
However, if you look at the code above, you'll see you're actually going to supply it like so:
Authorization: Bearertoken
which isn't going to work. Therefore, change your code to be:
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
// ---------------------------------------------------------^ Notice I've added a space here.
The code you show does not have the UseAuthorization() declaration.
In .NET 6 I am doing:
builder.Services.AddAuthentication(opt =>
{
opt.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:XXXX";
options.Audience = "idwebclient";
options.TokenValidationParameters.ValidateAudience = false;
options.TokenValidationParameters.IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("XXXXXXXXXXXXXXXXXXXXXXXXX"));
});
Recap
In my case I was not using any Identity Server Yet I was providing the Host as a ValidIssuer.
It validated the Authority for the algo and keys which returned nothing, this caused the system to throw an unhandled exception.
Solved this By Removing options.Authority from JwtBearerOptions in AddJwtBearer(options => ...).
After that I faced the 401 ERROR, resolved it by removing options.Audience from JwtBearerOptions in AddJwtBearer(options => ...), Also added ValidateLifetime to TokenValidationParameters (which you can see below in part 1)
Code
PART (1) JWT Configuration
in .NET 6 :
builder.services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey)),
ValidateIssuer = jwtSettings.ValidateIssuer,
ValidIssuer = jwtSettings.ValidIssuer,
ValidateAudience = jwtSettings.ValidateAudience,
ValidAudience = jwtSettings.ValidAudience,
RequireExpirationTime = jwtSettings.RequireExpirationTime,
ValidateLifetime = jwtSettings.RequireExpirationTime,
ClockSkew = TimeSpan.FromDays(1),
};
});
Extra
GET your JWT Settings from Appsettings using Either this
Where
"JsonWebTokenKeys"
is the name of section in configuration :
var jwtSettings = new JwtSettings();
Configuration.Bind("JsonWebTokenKeys", jwtSettings);
builder.services.AddSingleton(jwtSettings);
//PART (1) => JWT Configuration goes here
//..
//..
OR this :
services.Configure<JwtSettings>(configuration.GetSection("JsonWebTokenKeys"));
using (ServiceProvider serviceProvider = services.BuildServiceProvider())
{
var jwtSettings = serviceProvider.GetRequiredService<IOptions<JwtSettings>>().Value;
//PART (1) => JWT Configuration goes here
//..
//..
}
I have simple code using angularjs,
$http.post(postToCreateURL, addingProducts, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function () {
})
.error(function () {
});
And I want bind this data to this Mvc controller
[HttpPost]
public JsonResult Create(ProductModel model)
{
NorthwindEntities db = new NorthwindEntities();
var products = db.Products.Select(s => new ProductModel
{
ProductName = s.ProductName,
SupplierID = s.SupplierID,
CategoryID = s.CategoryID,
QuantityPerUnit = s.QuantityPerUnit,
UnitPrice = s.UnitPrice,
UnitsInStock = s.UnitsInStock,
UnitsOnOrder = s.UnitsOnOrder,
ReorderLevel = s.ReorderLevel,
Discontinued = s.Discontinued
}).Take(5).ToList();
return Json(products, JsonRequestBehavior.AllowGet);
}
In this situation I'm getting null values. Thanks in advance!
Try this:
var request = {
ProductName: 'aa',
SupplierID: 'aa',
CategoryID: 'aa',
...
Discontinued: 'zzz'
}
$http.post(" URL IN HERE ", JSON.stringify(request), {
headers: {
'Content-Type': 'application/json'
}
})