When I send a put request to a user in my spring boot backend, I got a 403 forbidden response. But when I send the same request through postman it gets updates. Can anyone help me to correct my code? I'll put all the relevant code segments below. (front - angular-cli 12, back - spring boot)
front end requesting method
updateUser(userId: string, profilePic: string, shortDes: string, username: string, email: string, phoneNumber: string): Observable<any> {
const body: FormData = new FormData();
body.append('id', userId);
body.append('username', username);
body.append('email', email);
body.append('shortDes', shortDes);
body.append('profilePic', profilePic);
body.append('phoneNum', phoneNumber);
console.log(userId,username,)
return this.http.put<HttpResponse<any>>(environment.baseUrl + `/api/v1/users/` + userId, body,{
observe: 'response'
});
}
backend receiving method
#PutMapping(
value = "/{id}",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public ResponseEntity<?> updateUser( #ModelAttribute UserBody body, #PathVariable("id") int id){
if (body.getId() != id) {
return new ResponseEntity<>("Mismatch userId !!", HttpStatus.BAD_REQUEST);
} else if (true) {
// TODO: 5/26/2022 handle the multi part file size from this stage before save it
}
try {
String filePath = null;
if (body.getProfilePic() != null) {
filePath = fileService.saveUserProfilePicture(body.getProfilePic());
UserDTO user = bo.getUser(id);
fileService.deleteFile(user.getProfilePicture());
}
UserDTO dto = new UserDTO();
dto.setId(body.getId());
dto.setUsername(body.getUsername());
dto.setEmail(body.getEmail());
dto.setShortDescription(body.getShortDes());
dto.setProfilePicture(filePath);
dto.setContactNum(body.getPhoneNum());
bo.updateUserNormalDetails(dto);
return new ResponseEntity<>(dto, HttpStatus.CREATED);
} catch (NoSuchElementException e) {
return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
} catch (Exception e) {
return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
postman request
The error I get from the spring-boot backend when I send a put request from the front-end
2022-07-04 10:44:40.619 WARN 3068 --- [nio-8080-exec-7] o.springframework.validation.DataBinder : Skipping URI variable 'id' because request contains bind value with same name.
HTTP request via browser
Related
I try to delete an entity with a given id. However, when I try to fetch from my API, i get a 400 bad request error.
async deleteFood(foodId) {
const params = {
'id' : foodId
}
const rawResponse = await fetch("food/delete", {
method:"POST",
headers: {'Content-Type': 'application/json'},
body: params,
});
const content = await rawResponse.json();
}
In my SpringBoot log, it shows me the id parameter is missing:
WARN 7784 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'id' for method parameter type int is not present]
I already tried putting params into JSON.stringify(), but this doesn't change anything.
Controller code:
#PostMapping(path = "/delete")
public #ResponseBody int deleteById(#RequestParam int id) {
if (foodRepository.existsById(id)) {
foodRepository.deleteById(id);
return Response.SC_ACCEPTED;
}
return Response.SC_BAD_REQUEST;
}
You are sending the data via body, but in the controller you are waiting that as a #RequestParam
#PostMapping(path = "/delete")
public #ResponseBody int deleteById(#RequestParam int id) {
if (foodRepository.existsById(id)) {
foodRepository.deleteById(id);
return Response.SC_ACCEPTED;
}
return Response.SC_BAD_REQUEST;
}
You need to either change the way you receive id param (#RequestBody instead of #RequestParam) some like:
#PostMapping(path = "/delete")
public #ResponseBody int deleteById(#RequestBody int id) {
if (foodRepository.existsById(id)) {
foodRepository.deleteById(id);
return Response.SC_ACCEPTED;
}
return Response.SC_BAD_REQUEST;
}
or change the way you're sending from React (send it as a url param)
I am using Javascript Fetch API to invoke Dot net web API.
Using Visual Studio code for HTML/Javascript & Visual Studio 2019 for Dot Net Web API.
I am trying to implement login functionality using Dot net C# Web API, that will return JWT token in the response and use the token later to invoke separate Web API/Service (e.g. EmployeeInfo ).
Login page :
It displays user id and password fields and the button "Login"
Once user clicks on login button, the function fnlogin is invoked
function fnlogin() {
const uname = document.getElementById('uname').value;
const pwd = document.getElementById('pwd').value;
const logindata = {
username: uname,
password: pwd
}
const loginurl = 'http://localhost:13402/api/Auth/Login';
authenticate(loginurl, logindata);
}
async function authenticate(loginurl, logindata) {
console.log(logindata)
const response = await fetch(loginurl , {
method: "POST",
mode: "cors",
body: JSON.stringify(logindata),
headers: { "Content-type" : "application/json, charset=UTF-8"}
});
const rdata = await response.json();
console.log(rdata);
if (!rdata.success) {
document.getElementById("loginMessage").innerHTML = rdata.message;
return;
}
const inMemoryToken = rdata.data
localStorage.setItem('user', JSON.stringify(rdata));
window.location.href = "http://localhost:5500/Employeeinfo1.html";
}
The Web API returns JWT token properly.
The code in controller is as follows :
[HttpPost("Login")]
public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
{
var response = await _authRepo.Login(
request.Username, request.Password
);
if (!response.Success)
{
return BadRequest(response);
}
return Ok(response);
}
``
The code in AuthRepository class is as follows :
public class AuthRepository : IAuthRepository
{
private readonly AppDbContext _context;
private readonly IConfiguration _configuration;
public AuthRepository(AppDbContext context, IConfiguration configuration)
{
_configuration = configuration;
_context = context;
}
public async Task<ServiceResponse<string>> Login(string username, string password)
{
var response = new ServiceResponse<string>();
var user = await _context.Users.FirstOrDefaultAsync(x => x.Username.ToLower().Equals(username.ToLower()));
if (user == null)
{
response.Success = false;
response.Message = "User not found.";
}
else if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
{
response.Success = false;
response.Message = "Wrong password.";
}
else
{
response.Data = CreateToken(user);
}
return response;
}
public async Task<ServiceResponse<User>> Register(User user, string password)
{
ServiceResponse<User> response = new ServiceResponse<User>();
if (await UserExists(user.Username))
{
response.Success = false;
response.Message = "User already exists.";
return response;
}
CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
_context.Users.Add(user);
await _context.SaveChangesAsync();
response.Data = user;
return response;
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username.ToLower().Equals(username.ToLower())))
{
return true;
}
return false;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != passwordHash[i])
{
return false;
}
}
return true;
}
}
private string CreateToken(User user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username)
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("AppSettings:Token").Value));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
var tokendDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = System.DateTime.Now.AddDays(1),
SigningCredentials = creds
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokendDescriptor);
return tokenHandler.WriteToken(token);
}
4. Once the JWT token is returned , it is stored in LocalStorage. I verified in Chrome Dev Tools
But after the next screen is displayed, when I check in Chrome dev tools, the object/token is no longer present in the Local Storage.
Is this because of window.location.href will remove all local data in localStorage in the browser ?
I want to be able to use the token to pass to remaining html screens and web api
You are storing an item in the local storage of http://127.0.0.1:5500 and trying to read it from http://localhost:5500.
From Window.localStorage in MDN Web Docs:
The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin;
And about Origin:
Web content's origin is defined by the scheme (protocol), host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match.
As you see, for the browser the origins are different because the host does not match: 127.0.0.1 is not the same string as localhost.
Use either localhost or 127.0.0.1 everywhere, but do not use both.
I tried to use Paypal Checkout SDK V2 in my Asp.Net MVC 5 project with .Net Framework 4.7.2 the but this seems to be something missing or wrong from my side.
I am just trying to integrate Paypal Checkout sdk and want to create an order so that my payment 'll be proceed by some paypal user and I only want to show one Pay Now button.
The SDK link is here:
https://github.com/paypal/Checkout-NET-SDK
and followed these links
https://developer.paypal.com/docs/checkout/reference/server-integration/get-transaction/#on-the-client
https://developer.paypal.com/demo/checkout/#/pattern/server
This is my code for trying it
C# Code
public class CheckoutController : Controller
{
public ActionResult Index()
{
ViewBag.ClientId = PayPalClient.ClientId;
ViewBag.CurrencyCode = "GBP"; // Get from a data store
ViewBag.CurrencySign = "£"; // Get from a data store
return View();
}
//[Route("api/paypal/checkout/order/create")]
public async static Task<HttpResponse> createOrder()
{
HttpResponse response;
// Construct a request object and set desired parameters
// Here, OrdersCreateRequest() creates a POST request to /v2/checkout/orders
var order = new OrderRequest()
{
CheckoutPaymentIntent = "CAPTURE",
PurchaseUnits = new List<PurchaseUnitRequest>()
{
new PurchaseUnitRequest()
{
AmountWithBreakdown = new AmountWithBreakdown()
{
CurrencyCode = "USD",
Value = "100.00"
}
}
},
ApplicationContext = new ApplicationContext()
{
ReturnUrl = "https://www.example.com",
CancelUrl = "https://www.example.com"
}
};
// Call API with your client and get a response for your call
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
response = await PayPalClient.Client().Execute(request);
var statusCode = response.StatusCode;
Order result = response.Result<Order>();
Console.WriteLine("Status: {0}", result.Status);
Console.WriteLine("Order Id: {0}", result.Id);
Console.WriteLine("Intent: {0}", result.CheckoutPaymentIntent);
Console.WriteLine("Links:");
foreach (LinkDescription link in result.Links)
{
Console.WriteLine("\t{0}: {1}\tCall Type: {2}", link.Rel, link.Href, link.Method);
}
return response;
}
public async static Task<HttpResponse> captureOrder()
{
// Construct a request object and set desired parameters
// Replace ORDER-ID with the approved order id from create order
var request = new OrdersCaptureRequest("APPROVED-ORDER-ID");
request.RequestBody(new OrderActionRequest());
HttpResponse response = await PayPalClient.Client().Execute(request);
var statusCode = response.StatusCode;
Order result = response.Result<Order>();
Console.WriteLine("Status: {0}", result.Status);
Console.WriteLine("Capture Id: {0}", result.Id);
return response;
}
/// <summary>
/// This action is called when the user clicks on the PayPal button.
/// </summary>
/// <returns></returns>
//[Route("api/paypal/checkout/order/create")]
public async Task<SmartButtonHttpResponse> Create()
{
var request = new PayPalCheckoutSdk.Orders.OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(OrderBuilder.Build());
// Call PayPal to set up a transaction
var response = await PayPalClient.Client().Execute(request);
// Create a response, with an order id.
var result = response.Result<PayPalCheckoutSdk.Orders.Order>();
var payPalHttpResponse = new SmartButtonHttpResponse(response)
{
orderID = result.Id
};
return payPalHttpResponse;
}
/// <summary>
/// This action is called once the PayPal transaction is approved
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
//[Route("api/paypal/checkout/order/approved/{orderId}")]
public ActionResult Approved(string orderId)
{
return Json("Sucess", JsonRequestBehavior.AllowGet);
}
/// <summary>
/// This action is called once the PayPal transaction is complete
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
//[Route("api/paypal/checkout/order/complete/{orderId}")]
public ActionResult Complete(string orderId)
{
// 1. Update the database.
// 2. Complete the order process. Create and send invoices etc.
// 3. Complete the shipping process.
return Json("Completed", JsonRequestBehavior.AllowGet);
}
/// <summary>
/// This action is called once the PayPal transaction is complete
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
//[Route("api/paypal/checkout/order/cancel/{orderId}")]
public ActionResult Cancel(string orderId)
{
// 1. Remove the orderId from the database.
return Json("Cancel", JsonRequestBehavior.AllowGet);
}
/// <summary>
/// This action is called once the PayPal transaction is complete
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
//[Route("api/paypal/checkout/order/error/{orderId}/{error}")]
public ActionResult Error(string orderId,
string error)
{
// Log the error.
// Notify the user.
string temp = System.Web.HttpUtility.UrlDecode(error);
return Json(temp, JsonRequestBehavior.AllowGet);
}
}
public static class OrderBuilder
{
/// <summary>
/// Use classes from the PayPalCheckoutSdk to build an OrderRequest
/// </summary>
/// <returns></returns>
public static OrderRequest Build()
{
// Construct a request object and set desired parameters
// Here, OrdersCreateRequest() creates a POST request to /v2/checkout/orders
OrderRequest order = new OrderRequest()
{
CheckoutPaymentIntent = "CAPTURE",
PurchaseUnits = new List<PurchaseUnitRequest>()
{
new PurchaseUnitRequest()
{
AmountWithBreakdown = new AmountWithBreakdown()
{
CurrencyCode = "USD",
Value = "100.00"
}
}
},
ApplicationContext = new ApplicationContext()
{
ReturnUrl = "https://www.example.com",
CancelUrl = "https://www.example.com"
}
};
// Call API with your client and get a response for your call
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
return order;
}
}
public class PayPalClient
{
public static string ClientId = " your client id";
public static string Secrets = "your client secret";
public static string SandboxClientId { get; set; } =
"<alert>{SandboxClientId}</alert>";
public static string SandboxClientSecret { get; set; } =
"<alert>{SandboxClientSecret}</alert>";
public static string LiveClientId { get; set; } =
"<alert>{PayPal LIVE Client Id}</alert>";
public static string LiveClientSecret { get; set; } =
"<alert>{PayPal LIVE Client Secret}</alert>";
public static PayPalEnvironment Environment()
{
//return new SandboxEnvironment("<alert>SandboxClientId</alert>",
// "<alert>SandboxClientSecret</alert>");
return new SandboxEnvironment(ClientId, Secrets);
}
public static PayPalCheckoutSdk.Core.PayPalHttpClient Client()
{
return new PayPalHttpClient(Environment());
}
public static PayPalCheckoutSdk.Core.PayPalHttpClient Client(string refreshToken)
{
return new PayPalHttpClient(Environment(), refreshToken);
}
public static String ObjectToJSONString(Object serializableObject)
{
MemoryStream memoryStream = new MemoryStream();
var writer = JsonReaderWriterFactory.CreateJsonWriter(memoryStream,
Encoding.UTF8,
true,
true,
" ");
var ser = new DataContractJsonSerializer(serializableObject.GetType(),
new DataContractJsonSerializerSettings
{
UseSimpleDictionaryFormat = true
});
ser.WriteObject(writer,
serializableObject);
memoryStream.Position = 0;
StreamReader sr = new StreamReader(memoryStream);
return sr.ReadToEnd();
}
}
public class SmartButtonHttpResponse
{
readonly PayPalCheckoutSdk.Orders.Order _result;
public SmartButtonHttpResponse(PayPalHttp.HttpResponse httpResponse)
{
Headers = httpResponse.Headers;
StatusCode = httpResponse.StatusCode;
_result = httpResponse.Result<PayPalCheckoutSdk.Orders.Order>();
}
public HttpHeaders Headers { get; }
public HttpStatusCode StatusCode { get; }
public PayPalCheckoutSdk.Orders.Order Result()
{
return _result;
}
public string orderID { get; set; }
}
View html is
<!-- Set up a container element for the PayPal smart button -->
<div id="paypal-button-container"></div>
#section scripts
{
<script src="https://www.paypal.com/sdk/js?client-id=#ViewBag.ClientId"></script>
<script type="text/javascript">
var orderId;
function httpGet(url) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, false);
xmlHttp.send(null);
return xmlHttp.responseText;
}
paypal.Buttons({
// Set up the transaction
enableStandardCardFields: true,
createOrder: function (data, actions) {
orderId = data.orderID;
console.log("Start");
console.log(data);
console.log(actions);
console.log("End");
return fetch(
'/PaypalPayments/create/', {
method: 'post'
}).then(function (res) {
return res.json();
}).then(function (data) {
return data.orderID;
});
},
// Finalise the transaction
onApprove: function (data, actions) {
return fetch('/PaypalPayments/approved/' + data.orderID, {
method: 'post'
}).then(function (res) {
return actions.order.capture();
}).then(function (details) {
// (Preferred) Notify the server that the transaction id complete
// and have an option to display an order completed screen.
window.location.replace('/PaypalPayments/complete/' +
data.orderID + '/#ViewBag.CurrencyCode');
// OR
// Notify the server that the transaction id complete
//httpGet('/api/paypal/checkout/order/complete/' + data.orderID);
// Show a success message to the buyer
alert('Transaction completed by ' + details.payer.name.given_name + '!');
});
},
// Buyer cancelled the payment
onCancel: function (data, actions) {
httpGet('/PaypalPayments/cancel/' + data.orderID);
},
// An error occurred during the transaction
onError: function (err) {
debugger;
fetch(
'/PaypalPayments/error/', {
method: 'post',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ orderId: orderId, error: encodeURIComponent(err)})
}).then(function (res) {
return res.json();
}).then(function (data) {
return data.orderID;
});
}
}).render('#paypal-button-container');
</script>
}
The error which I 'll have to receive is given below:
My create post request is successful by returning 200 status.
After this request, the control instantly goes to Error function and throwing this error.
Error: Unexpected token P in JSON at position 0"
The complete error detail is mentioned below
SyntaxError: Unexpected token P in JSON at position 0
Error: Unexpected token P in JSON at position 0
at Qt.error (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:60544)
at Object.<anonymous> (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68311)
at JSON.parse (<anonymous>)
at o (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68170)
at dr (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68323)
at u.on (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:72994)
at br (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:73131)
at https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:79250
at Function.n.try (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:14118)
at https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:79047
Error: Unexpected token P in JSON at position 0
at Qt.error (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:60544)
at Array.<anonymous> (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68311)
at JSON.parse (<anonymous>)
at o (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68170)
at dr (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:68323)
at u.on (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:72994)
at br (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:73131)
at https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:79250
at Function.n.try (https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:14118)
at https://www.paypal.com/sdk/js?client-id=ATiT9hZAk22xK68Sg9cE3qg24jH1GP9eTm6XW2O47fPl3cligEblR35E1f24OnLg8XOmD7Y_tcnHDhPZ:2:79047
Can anybody guide me properly? I tried different articles but I am still getting these errors.
When you fetch /PaypalPayments/create/ from your server , what do you get back?
Obviously you aren't getting back valid JSON, but your code is trying to parse it as JSON.
Change your server code to only give back valid JSON. The code actually seems okay, so perhaps there is something wrong with the /PayPalPayments/create/ route that is hardcoded in the client-side code.
It would also be wise to change your client-side code to follow the best sample available, which is at https://developer.paypal.com/demo/checkout/#/pattern/server and demonstrates how to properly handle errors for the capture
(Just noticed the code in your example uses actions.order.capture() combined with this server-side integration, which is rather awful -- seems the server-side captureOrder task never even gets called, which is rather the whole point of using server-side APIs in the first place, if you don't capture from the server you get none of the benefits)
This is similar to below but without Ajax. I am using JavaScript and XMLHttpRequest
AJAX post data is null when it reaches the ASP.NET Core 2.1 controller
Everything works good in ASP.NET MVC but I am learning ASP.NET Core MVC.
A button in Home.cshtml calls below JavaScript method which intern calls a method named Test in HomeController.cs.
My problem is if I keep break point in my Test method serverName and port are both null
function MyMethod() {
var xmlhttp = new XMLHttpRequest();
var url = "/Home/Test";
var input = {};
input.serverName = document.getElementById("serverName").value;
input.port = document.getElementById("port").value;
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var jsResp = JSON.parse(xmlhttp.responseText);
if (jsResp.Status == "Success") {
//show success
}
else {
//show error
}
}
}
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(JSON.stringify(input));
}
[HttpPost]
public JsonResult Test(string serverName, string port)
{
try
{
if (string.IsNullOrEmpty(serverName) ||
string.IsNullOrEmpty(port))
{
return Json(new { Status = "Error", Message = "Missing Data" });
}
else
{
return Json(new { Status = "Success", Message = "Got data" });
}
}
catch (Exception e)
{
return Json(new { Status = "Error", Message = e.Message });
}
}
I even tried below but none helps
public JsonResult Test(JObject serverName, JObject port) -- controller method not hiting
public JsonResult Test(object serverName, object port) -- not allowing me to cast into string
public JsonResult Test([FromBody] string serverName, [FromBody] string port)
Since your content type is application/json;charset=UTF-8, you need to use [FromBody] and receive the data as an object based on your situation.
Besides, you could only use [FromBody] in the action parameters once(from here)
Don't apply [FromBody] to more than one parameter per action method. The ASP.NET Core runtime delegates the responsibility of reading the request stream to the input formatter. Once the request stream is read, it's no longer available to be read again for binding other [FromBody] parameters.
You could follow below steps to pass data correctly:
1.Create a ViewModel:
public class ServerModel
{
public string serverName { get; set; }
public string port { get; set; }
}
2.Action:
[HttpPost]
public JsonResult Test([FromBody] ServerModel data)
{
try
{
if (string.IsNullOrEmpty(data.serverName) ||
string.IsNullOrEmpty(data.port))
{
return Json(new { Status = "Error", Message = "Missing Data" });
}
else
{
return Json(new { Status = "Success", Message = "Got data" });
}
}
catch (Exception e)
{
return Json(new { Status = "Error", Message = e.Message });
}
}
I need to create a Websocket Server using spring which was easily completed by using the below code
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/poll");
registry.addHandler(new SocketPushHandler(), "/push");
}
}
Where SocketHandler and SocketPushHandler are the handler classes for the websocket endpoints.
Till this very thing is good able to run the server and connect to the endpoint using normal socket = new WebSocket(websocketUrl) javascript code.
Now we need to have OAuth 2.0 Security implemented on the API endpoints which is done easily by importing some Spring security dependencies.\
Now the hard part is writing the client to connect the secure endpoint by passing the Oauth Authorization beaer <token> as part of header.
From documents came to know that we can't send headers to Web-socket endpoints.
So according to the information form this Is it possible to secure WebSocket APIs with OAuth 2.0? link I created a API gateway /open-ws Request type GET to which the client would connect and send the authorization headers and this endpoint internally on server-side will open an WebSocket Client connection passing the the headers as javax.websocket.WebSocketContainer supports websocket client with custom headers.
So now my javascript first makes an GET ajax call to the Gateway endpoint and on success makes an new websocket request.
Below is the Spring API mimicking as gateway
#RequestMapping(value = "/open-ws", method = RequestMethod.GET)
public void getOperatorTokenDefinition(#RequestHeader(value = HttpHeaders.AUTHORIZATION) String bearerToken,
#RequestHeader(value = "websocketURL") String websocketURL,
HttpServletRequest acquireTokenServletRequest, HttpServletResponse response) {
webSocketClient.connecttoserver(websocketURL, acquireTokenServletRequest.getRemoteHost(), bearerToken, response);
// ResponseEntity<String> responseEntity = new ResponseEntity<>("connected", HttpStatus.OK);
}
}
Below is my Spring side client.
#Component
public class WebSocketClient {
private Session client;
public void connecttoserver(String websocketURL,String host,String bearerAccessToken, HttpServletResponse response) {
final AtomicReference<String> message = new AtomicReference<>();
Endpoint endpoint = new Endpoint() {
#Override
public void onOpen(Session session, EndpointConfig config) {
System.out.println("WSS OPEN!!!!!");
try (OutputStream output = response.getOutputStream()) {
output.write(session.getId());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
ClientEndpointConfig.Configurator configurator = new ClientEndpointConfig.Configurator() {
#Override
public void beforeRequest(Map<String, List<String>> headers) {
List<String> connection = new ArrayList<>(1);
connection.add("Upgrade");
List<String> origin = new ArrayList<>(1);
origin.add(originURL);
List<String> upgradeWebsocket = new ArrayList<>(1);
upgradeWebsocket.add("WebSocket");
List<String> host = new ArrayList<>(1);
host.add(websocketURL);
List<String> contenttype = new ArrayList<>(1);
contenttype.add("application/json");
List<String> authorization = new ArrayList<>(1);
authorization.add("Bearer " + bearerAccessToken);
List<String> tenantId = new ArrayList<>(1);
tenantId.add(tenantID);
List<String> key = new ArrayList<>(1);
key.add("HcFOxrSD89ya65X2qMF9lQ==");
List<String> version = new ArrayList<>(1);
version.add("13");
headers.put("Connection", connection);
headers.put("Upgrade", upgradeWebsocket);
headers.put("Host", host);
headers.put("Origin", origin);
// headers.put("Content-Type", contenttype);
headers.put("Authorization", authorization);
headers.put("Sec-WebSocket-Key", key);
headers.put("Sec-WebSocket-Version", version);
}
};
ClientEndpointConfig clientConfig = ClientEndpointConfig.Builder.create().configurator(configurator).build();
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
// if (!this.client.isOpen())
this.client = container.connectToServer(endpoint, clientConfig, URI.create(websocketURL));
client.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String response) {
// TODO Auto-generated method stub
message.set(response);
// System.out.println("response>>>>>>>>>>>>>>>>>>> "+response.toString());// this dosent work
}
});
System.out.println("Response--------------------------------->" + message.get());
// client.close();
} catch (DeploymentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Below is the JQuery code
$(document).ready(function(){
$("#Websocketconnect").click(function(){
$.ajax({
type: 'GET',
url: hostUrl.value,
headers: {
"Authorization":websocketToken.value,
"websocketURL":websocketUrl.value,
"Content-type":"text/plain"
},
success: function(result){
$("#readystatus").value = result;
webSocketCycleEvent(websocketUrl.value);
}});
});
});
function webSocketCycleEvent(websocketUrl){
socket = new WebSocket(websocketUrl);
socket.onerror = function(error) {
console.log('WebSocket Error: ' + error);
};
// Show a connected message when the WebSocket is opened.
socket.onopen = function(event) {
socketStatus.innerHTML = 'Connected to: ' + websocketUrl;
socketStatus.className = 'open';
};
socket.onmessage = function(event) {
var message = event.data;
messagesList.innerHTML += '<li class="received"><span>Received:</span>' +
message + '</li>';
};
socket.onclose = function(event) {
socketStatus.innerHTML = 'Disconnected from WebSocket.';
socketStatus.className = 'closed';
};
}
form.onsubmit = function(e) {
e.preventDefault();
// Retrieve the message from the textarea.
var message = messageField.value;
socket.send(message);
messagesList.innerHTML += '<li class="sent"><span>Sent:</span>' + message +
'</li>';
// Clear out the message field.
messageField.value = '';
return false;
};
I am not to connect to the websocket and send the socket.id as the server-side gives an
javax.websocket.DeploymentException: The HTTP response from the server [400] did not permit the HTTP upgrade to WebSocket
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:343)
at com.example.simplewebsocketserver.WebSocketClient.connecttoserver(WebSocketClient.java:101)
at com.example.simplewebsocketserver.WebSocketController.getOperatorTokenDefinition(WebSocketController.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
So the Question arises is this the proper way of connecting the Oauth 2.0 Websocket, if yes how to deal with the above error, if no how to send headers to the authorization endpoint.
Note: No using Stomp because we are not yet confirmed whether the actual client i.e UI will allow/have stomp JS.