How to send post request from angular app to spring? - java

I am trying to send port request with username and password:
signUp(username, password): Observable<String> {
return this.http.post<String>("http://localhost:8080/signUp", {
params: { username: username, password: password }
});
}
To a spring service that has this method:
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value="/signUp", method=RequestMethod.POST)
public ResponseEntity<String> signUp(#RequestParam ("username") String username, #RequestParam("password") String password) throws IOException {
//not important
return new ResponseEntity<String>("Added successfully.", HttpStatus.OK);
}
When I send it, in angular I get http 400 error. In spring service I see this message:
2020-03-13 19:32:38.486 WARN 13200 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'username' is not present]
I know that there are values sent from Angular application in that http request (I checked with hardcoded). Can someone help me solve it? Thanks in advance.

Seems like there is a confusion between #RequestBody and #RequestParam - they're two entirely different things.
#RequestBody Indicates that the API is expecting a request payload
and
#RequestParam expects one or more params to be passed in to the API
url when it is invoked.
Now, the backend expects a request parameter to be passed in when it is invoked. For eg: /signUp/username=abc, so from the UI you need to pass in this key-value pair i.e
http.post<String>(`http://localhost:8080/signUp?username=${username}&password=${password}`)
The 400 bad request originates as you are passing in a request body rather than a request parameter. An alternate solution is to change the backend to accept a request payload - you would then need to use #RequestBody.

A possible solution could be this request:
signUp(username, password): Observable<String> {
return this.http.post<String>("http://localhost:8080/signUp", {
username: username, password: password
});
}
...with a class for the request body in your backend:
public class SignUp {
private String username;
private String password;
// constructor, getters and setters or lombok #Data
}
...and then in your controller:
#RequestMapping(value="/signUp", method=RequestMethod.POST)
public ResponseEntity<String> signUp(#RequestBody SignUp signUp) {
// signUp.getUsername()...
return new ResponseEntity<String>("Added successfully.", HttpStatus.OK);
}

Related

Form application encoded value is not working in spring rest

I have the below post request and of which below is the controller code
#RestController
#RequestMapping(/flow", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#Override
#ResponseStatus(HttpStatus.OK)
#PostMapping("{abcCode}/token")
public TokenResponse createToken(#PathVariable("abcCode") String abcCode,
#RequestParam("grant_type") String grantType,
#RequestParam String code,
#RequestParam("redirect_uri") String redirectUri,
#RequestParam String clientId) {
LOG.info(
"Received call for createIdToken for abcCode: {} , clientId: {} , grantType: {} ,code: {} , redirectUri: {}",
abcCode, clientId, grantType, code, redirectUri);
}
Now the problem is that when I test the same above controller through postman by choosing the body type as application form-encoded then it is working fine but when I choose the body type as none in postman and just pass the above request parameters as query one then also it works which ideally it should not please advise how can I overcome from the same
http://localhost:19080/testService/flow/token?grant_type=authorization_code&code=3272&redirect_uri=http://www.abchui.com&clientId=ATS
it should not work for the above URL
From spring sources:
public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
According to docs, when using url-form-encoded data pass as query params.
Try to change form mime type.

Receiving a POST Request on Spring From Another Site

I'm a little new in Java Spring. What I want to do is as follows:
Some 3rd party is asking a "return URL" from me and I set it as follows:
https://localhost:9002/my-account/order-history
Then they send me a POST request and I'm supposed to handle it within my controller. The request has both url parameters and a form data. The request is
Request URL:https://localhost:9002/my-account/order-history?responseCode=0000&token=E0ECFC1214B19E5D11B9B587920FC5F164C5CB17E7DC67F083E0EC6676F79467DFBDF4B6CCF3C39BF47F0232D1AA42F1FA112F29B0157DDF98EE3997F781CCB1FEB070A44E530691BA36674BEA4CF56A4A43F2B9746D9C3591CF288D745A6694
Request Method:POST
Status Code:403 Bad or missing CSRF token
Remote Address:127.0.0.1:9002
Referrer Policy:no-referrer-when-downgrade
A part of the form data is:
I added the whole form data and other request info as attachment.
The controller I'm desperately trying to use is as follows:
#Controller
#RequestMapping(value = "/my-account")
public class MaviAccountPageController extends MaviAbstractController
{
#RequestMapping(value = "/order-history", method = RequestMethod.POST)
public ModelAndView process(#RequestBody final String req)
{
//consumes = "text/plain"
System.out.println(req);
System.out.println(req);
return new ModelAndView("deneme");
}
....
}
And I keep getting 403 - Bad or missing CSRF token error.
How should I implement my controller? I have checked below links and they did not work out unfortunately:
How to retrieve FORM/POST Parameters in Spring Controller?
How to explicitly obtain post data in Spring MVC?
I tried, but failed to regenerate issue on postman.
Can anyone, please, advise me about how to move on?
you can annotate your method with #CrossOrigin
#CrossOrigin
#RequestMapping(value = "/order-history", method = RequestMethod.POST)
public ModelAndView process(#RequestBody final String req)
{
//consumes = "text/plain"
System.out.println(req);
System.out.println(req);
return new ModelAndView("deneme");
}
https://spring.io/guides/gs/rest-service-cors/

Request Header is getting as null in spring mvc

I am having two mapping methods in my controller. one is redirecting to other.
Before redirecting I'm setting a header in response. But I getting the request header as null.
These are my methods in controller. both are in same controller.
#RequestMapping(value="/testStart", method=RequestMethod.POST)
public String testStart(HttpServletRequest request, HttpServletResponse response){
String token = "126712810-1289291":
response.addHeader("authToken", token);
return "redirect:/test";
}
#RequestMapping(value="/test", method={ RequestMethod.POST, RequestMethod.GET })
public String getTestPage(Model model, HttpServletRequest request, HttpServletResponse response){
String token = request.getHeader("authToken");
System.out.println(token); //prints null
model.addAttribute("Testtoken", token);
System.out.println("Test page about to load ..");
return "test";
}
I'm using postman client to test this api. It is hitting the url and redirecting to other url. but the header is null.
I don't know what's wrong. can any one help me to figure this out? Thanks
With Redirect method web app tells browser to load the page which you want to redirect. So this makes new http request from browser, the original requests are not reachable at this moment.
So your problem can be solved with Forward method. Web app forwards all request data to another handler method internally
return "forward:/test";
Additionally , please change your
String token = request.getHeader("authToken");
with
String token = response.getHeader("authToken");
because you are adding your authToken to the response object.(from comments HttpServletResponse -> getHeader(String name) works since Servlet 3.0)
EDIT :
this code will be your complete solution "/test" method supports forwarded reuqest and also supports request from browser.
(You want to get token info from request becuase you want to call /test method without forwarding, so it works in this way, but when forwarding you cant add header so you tried to add in response and get it from request but that doesnt work in that way so you need to resolve token according to dispatcher's type so check the code )
#RequestMapping(value="/testStart", method=RequestMethod.POST)
public String testStart(HttpServletRequest request, HttpServletResponse response){
String token = "126712810-1289291";
request.setAttribute("authToken", token);
return "forward:/test";
}
#RequestMapping(value="/test", method={ RequestMethod.POST, RequestMethod.GET })
public String getTestPage(Model model, HttpServletRequest request, HttpServletResponse response)
{
//-----------------
//resolving token
String token = null;
DispatcherType type = request.getDispatcherType();
if(type == DispatcherType.FORWARD)
{
token = (String) request.getAttribute("authToken");
}
else if(type == DispatcherType.REQUEST)
{
token = (String) request.getHeader("authToken");
}
//-----------------
System.out.println(token); //prints the value
model.addAttribute("Testtoken", token);
System.out.println("Test page about to load ..");
return "test";
}
Use RedirectAttributes to pass parameters with redirect URL:
#RequestMapping(value="/test1", method=GET)
public String test(RedirectAttributes redirectAttributes){
redirectAttributes.addAttribute("authToken", "val");
return "redirect:/test";
}
or if you can use forward:/test you can go with request.setAttribute and request.getAttribute
Still if you want to add in header then use RestTemplate and HTTPHeaders and get the response String

How to login with #RestController and send the object to angularjs

I have some trouble figuring out how to create a login form in angularjs using springboot.
I can register a user and send the data to the database but the problems begin when i want to login.
in angularjs i have a function like this
function Login(username, password, callback) {
$http.post('/api/authenticate', { username: username, password: password })
.success(function (response) {
callback(response);
});
}
What i managed to do but probably is't right:
#RequestMapping(value = "/authenticate/{id}",method = RequestMethod.GET)
public User getUser(#PathVariable Integer id) {
return repo.findOne(id);
}
This gives me following json
{"id":2,"username":"jdoe","password":"$2a$10$5hgIyQr.K9wb8cXEyWGbROAU.rkYzd19vP7ajHpwp1KUYdShfcPn.","lastname":"doe","firstname":"john","customfield":"Hello there"}
But now i have following problems and questions :
How can i check if the username and password is equal to the username and password of json by going to api/authenticate ? (without {id})
can i hide this json from the users ?
Is this safe ?
how will angular now all the users propertys ? (i suggest i can retrieve this from the json)
any pro tips on how to solve this?
From AngularJS you are calling HTTP POST method and at Spring side you have declared as HTTP GET, which is wrong.
Correct request mapping is
#RequestMapping(value = "/api/authenticate",method = RequestMethod.POST, consumes = "application/json")
#ResponseBody
public User getUser(#RequestBody User user) {
//here request body contains User POJO object's payload (JSON object)
//You are getting username from JSON,
//so you need to update your call to findOne method
return repo.findOne(user.getUserName());
}
Please refer
#RequestBody and #ReponseBody spring
#RequestBody annotation spring docs
#RequestMapping#consumes

cant get correct session id to login to spring security with retrofit

I'm trying to create automated, end to end, tests to my webapp by making rest calls (using retrofit). our rest calls are protected with spring security, so i have to login first.
To my best understanding, i need to call /j_spring_security_check with user/password, get the returned "Set-cookie" response header and set it as a "Cookie" request header on each rest call i perform.
It seems like my call to spring login "page" is successful as we have implemented an ApplicationListener which logs each successful login attempt,
however, the returned response from the call to j_spring_security_check has a status 200 (should be 302 as the apps redirects after successful login) and the body of the response is the login page itself.
What am i doing wrong?
the login retrofit interface:
#FormUrlEncoded
#POST("/j_spring_security_check")
Response basicLogin(#Field("user") String user, #Field("password") String pwd);
the code to call spring's login:
public static void login(String user, String pwd) {
PortalLoginService loginService = PortalRestAdapter.getInstance().createLoginService();
Response response = loginService.basicLogin(user, pwd);
String setCookieHeader = getSetCookieHeader(response.getHeaders());
AuthCookieInterceptor.getInstance().setSessionId(setCookieHeader);
}
private static String getSetCookieHeader(List<Header> headers) {
for (Header header : headers) {
if (SET_COOKIE_HEADER_NAME.equals(header.getName())) {
return header.getValue();
}
}
return null;
}
code of AuthCookieInterceptor intercpet method:
#Override
public void intercept(RequestFacade requestFacade) {
if (sessionId != null) {
requestFacade.addHeader("Cookie", sessionId);
}
}
the rest adapter init:
restAdapter = new RestAdapter.Builder()
.setRequestInterceptor(AuthCookieInterceptor.getInstance())
.setEndpoint(PORTAL_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
so basically I'm making a call to login, and setting the returned session id from the login response on each request i make after (using request interceptor)
Thanks a lot
You need to change the name of the parameters passed, j_spring_security_check is expecting j_username and j_password instead of your
Response basicLogin(#Field("user") String user, #Field("password") String pwd);
Also, because in the case of this call, the spring framework is returning us a html response (keep in mind that we are doing a POST to servlet), we need to set our converter, so you need to do something like this:
SimpleXMLConverter converter = new SimpleXMLConverter();
RestAdapter adapter = builder.setLogLevel(RestAdapter.LogLevel.FULL).setConverter(converter).build();
then a simple call like this one:
Response response = LoginClient.getService().login("john", "john1");
and from the response object, you can get any information you could need
I have solved this puzzle.
Frist of all to authorize user you need to replace "user" with "username"
#FormUrlEncoded
#POST("/login")
Response autorizeMethod(#Field("username") String user, #Field("password") String pwd);
then disable auto redirection in retrofit
val client=OkHttpClient.Builder().followRedirects(false).build()
Retrofit.Builder()
.baseUrl("http://localhost:8080")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()

Categories