I am trying to authenticate a user's username and password using an Ajax call.The parameters are passed to java bean and it should return a success or a failure message string to the caller but it shows a Servlet service error.The code is as follows:
package com.eits.portal.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.eits.portal.service.OrgTreeService;
public class UserLoginController extends MultiActionController {
OrgTreeService orgTreeService;
ModelAndView mv;
public String getLoginStatus(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse)
throws Exception{
//paramHttpServletResponse.setContentType("application/json");
String userId = paramHttpServletRequest.getParameter("user");
String password = paramHttpServletRequest.getParameter("password");
String s="";
System.out.println("---node"+userId);
System.out.println("---node"+password);
String us="admin";
String pass="admin";
if(userId.equals(us)&& password.equals(pass)){
s="success";
System.out.println("success ");
}else{
s="failure";
System.out.println("unsuccessful");
}
return s;
}
public void setOrgTreeService(OrgTreeService paramOrgTreeService)
{
this.orgTreeService = paramOrgTreeService;
}
}
The code is pretty simple and it does print success on passing the right username and password in the IDE console , but the same string is not passing to the caller function for the front end.Here is a snapshot of the error I am getting :-
http://gyazo.com/12b386a9e586fc0ee5514800c9822071
Is this a right way to pass the success to the caller method , or should i pass an object instead of the string?
Firstly, if you are getting a 404 (Not Found) then you should check that you are calling the correct URL and that your servlet request mapping configuration is specified correctly, e.g. via #RequestMapping annotation if using Spring.
Then, assuming you are making a request similar to below, you can return a Json string from your controller method that will be returned in the response and can be decoded into an object, assuming you may want to pass back more details than simply "success" or "failure".
Ext.Ajax.request({
url: '/someUrl',
params: {
user: 'username',
password: 'password'
},
callback: function(options, success, response) {
if (success) {
var obj = Ext.decode(response.responseText);
....
}
}
});
Related
I have a Groovy Spring Boot microservice that returns a list of posts. Requests come into the controller, the controller invokes a method in a service class, and if no posts are found, a custom error message is thrown.
I've created a controller annotated with #ControllerAdvice that I want to intercept errors, and a handler specific to the custom error. It should return a POJO. At present the ControllerAdvice handler is being invoked, but the response from the microservice is a 500 error
The controller
#RequestMapping(value ='getCommentList', method = RequestMethod.POST)
def getCommentList(#RequestBody requestParams) {
def response
String userId = requestParams.userId
String uuid = requestParams.uuid
response = commentService.findCommentsByUserIdAndUuid(userId, uuid)
}
The service method
def findCommentsByUserIdAndUuid(String userId, String uuid) {
User user = userRepository.findByUserId(userId)
Long userId = tenant?.id
List responses = commentRepository.findCommentsByUserAndUuidNotDeleted(userId, uuid)
if (responses.size() == 0) {
throw new CommentsNotFoundException()
} else {
def data = JsonOutput.toJson(retMap)
return data
}
}
the custom exception class
package com.news.exception
class CommentsNotFoundException extends Exception {
String errorMessage
def dataReturned
public commentsNotFoundException() {
NewsFeedMessage.buildRequestErrorMessageWithData(errorMessage, dataReturned)
}
}
The POGO to be returned
package com.news.utils
import org.springframework.http.HttpStatus
class NewsFeedMessage {
int httpStatus
String type
String message
def dataReturned
def subMessages = []
static NewsFeedMessage buildRequestErrorMessageWithData(mainMessage, data) {
return new NewsFeedMessage(
httpStatus: 400,
message: mainMessage,
dataReturned: data
)
}
}
And the global exception handler with#ControllerAdvice annotation
package com.news.exception
import com.newa.utils.NewsFeedMessage
import org.springframework.boot.configurationprocessor.json.JSON
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.context.request.WebRequest
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(CommentsNotFoundException.class)
public NewsFeedMessage handleException() {
def response = NewsFeedMessage.buildRequestErrorMessageWithData("testing 1234", [])
//return response as JSON
}
}
When debugging, The code gets as far as
def response = NewsFeedMessage.buildRequestErrorMessageWithData("testing 1234", [])
However nothing is returned.
The returned message using Postman is:
{
"timestamp": "2020-10-23T16:27:35.572+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No message available",
"path": "/comment/getCommentList"
}
Is there anything here that is glaringly wrong?
I think NewsFeedMessage is not supported return type. Check ExceptionHandler docs and there is a block about supported return types. Try returning a ResponseEntity<>(new NewsFeedMessage()).
I have a very simple endpoint
#PostMapping("/exception")
public String exception() {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
in 2 different machines. On the first machine this code is in a very simple spring boot app and it works as it is supposed to be working - when invoked, it returns 400 BAD_REQUEST. On the second machine, I have real spring boot project, with a lot of stuff. There, instead of having BAD_REQUEST returned, i get 405 MethodNotAllowed.
I don't even know what can be causing this behavior. Do you have any idea what is the case?
I am attaching a screenshot of the postman request that I use.
Postman screenshot
The whole controller:
package com.xxx.service.max.web.controller;
import com.xxx.service.max.model.context.UserContext;
import com.xxx.service.max.services.cas.CustomerAccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import static com.xxx.service.max.constant.Constants.MY_ACCOUNT_X_REST;
#RestController
#RequestMapping(MY_ACCOUNT_X_REST)
public class ChangeLocaleController {
private static final Logger LOG = LoggerFactory.getLogger(ChangeLocaleController.class);
private UserContext userContext;
private CustomerAccountService customerAccountService;
#PostMapping("/exception")
public String exception() {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
#Autowired
public void setUserContext(UserContext userContext) {
this.userContext = userContext;
}
#Autowired
public void setCustomerAccountService(CustomerAccountService customerAccountService) {
this.customerAccountService = customerAccountService;
}
}
Make sure you are sending a POST request.
The 405 Method Not Allowed error occurs when the web server is configured in a way that does not allow you to perform a specific action for a particular URL. It's an HTTP response status code that indicates that the request method is known by the server but is not supported by the target resource.
Source
If you are simply entering the URL in your browser that is a GET request and you would get a 405.
I am working on creating an app using springboot which would consume an API which has OAuth2 authentication. Post successful getting the Bearer code I would be calling another API which would actually give me data for further processing. I have custom OAuth url, authorization code, username, password, secret key, api key. When I searched on internet, none of the example were usign all of these[only secret key, authorization code and api key was getting used.]. Do I need to use username and password as well?
I tried below code [and few other things]. But not able to get through this.
<code>
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.support.BasicAuthorizationInterceptor;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Component
public class ApiConsumer {
#Autowired
private RestTemplate template;
#Value("${oauth.api}")
String url;
#Value("${oauth.oAuth.url}")
String oAuthUrl;
#Value("${oauth.user}")
String username;
#Value("${oauth.password}")
String password;
#Value("${oauth.apikey}")
String apiKey;
#Value("${oauth.secretkey}")
String apiSecret;
public String postData() {
log.info("Call API");
try {
String response = consumeApi();
if (response.equals("200")) {
log.info("posting data to another api");
// CALL another API HERE for actual data with bearer code
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
private String consumeApi() throws Exception {
String authorizationHeader = "Basic "
+ DatatypeConverter.printBase64Binary((apiKey + ":" + apiSecret).getBytes());
// setting up the HTTP Basic Authentication header value
HttpHeaders requestHeaders = new HttpHeaders();
// set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE);
requestHeaders.add("response_type", "code");
// request entity is created with request headers
HttpEntity<String> request = new HttpEntity<String>(requestHeaders);
template.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));
ResponseEntity<String> result = null;
try {
result = template.exchange(oAuthUrl, HttpMethod.POST, request, String.class);
log.info( result.getBody());
if (result.getStatusCode() == HttpStatus.OK) {
transformData(result.getBody());
}
if (result.getStatusCode() != HttpStatus.REQUEST_TIMEOUT) {
throw new Exception("Api taking too long to respond! ");
}
}
catch (Exception e) {
log.error("Api taking too long to respond!");
}
return "";
}
private void transformData(String body) throws JsonMappingException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<HeapEntity> heapEntityList = Arrays.asList(mapper.readValue(body, HeapEntity[].class));
if (heapEntityList != null && heapEntityList.size() > 0) {
heapEntityList.forEach(i -> i.getPhoneNumber().replaceAll("-", ""));
}
log.debug("Size of list is :: " + heapEntityList.size());
heapEntityList.add(null);
}
}
</code>
Unfortunately, I cannot give a direct answer to your question, because it is not clear from it which grant type you are trying to use, and this will determine the answer to the question whether you need to use a username and password or not.
I advise you to familiarize yourself with the Section 4 of RFC 6749, in which you will find information on all grant types supported by the standard, and the request parameters they require.
Examples for the Password grant type:
If you need to use the RestTemplate, you can do something like this:
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString((clientId + ":" + clientSecret).getBytes()));
String body = String.format("grant_type=password&username=%s&password=%s", username, password);
String json = restTemplate.postForObject(tokenUrl, new HttpEntity<>(body, headers), String.class);
Note that the response is a json object containing a token, not the token itself.
Or you can simply use the more appropriate for your purpose OAuth2RestTemplate:
#Bean
public OAuth2RestTemplate oAuth2RestTemplate() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
resource.setAccessTokenUri("tokenUrl");
resource.setClientId("clientId");
resource.setClientSecret("clientSecret");
resource.setUsername("username");
resource.setPassword("password");
return new OAuth2RestTemplate(resource);
}
Do not forget to add #EnableOAuth2Client to one of your configuration classes.
I want try do a Post request from my frontend (Angular 2) to my backend (Spring). But I can't.
The error:
GET http://localhost:8080/loginPost 405 ()
Failed to load http://localhost:8080/loginPost: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.0.190:4200' is therefore not allowed access. The response had HTTP status code 405.
My Angular Service:
import {Injectable} from "#angular/core";
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Login } from'../data-login/models/login.model';
#Injectable()
export class LoginService{
private loginUrl = 'http://localhost:8080/loginPost'; // URL to web API
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http){}
loginQuery(login: Login){
console.log(login.id);
return this.http.request(this.loginUrl,JSON.stringify(login));
}
}
My Spring Backend Code:
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
public class LoginProvider {
#CrossOrigin(origins = "http://192.168.0.190:4200")
#PostMapping(value="/loginPost", consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE })
public ResponseEntity<?> verifyLogin(#RequestBody String maoe){
System.out.println(maoe);
return new ResponseEntity<>(HttpStatus.OK);
}
}
I need to read the Json sent by my frontend, checking and responding with OK, no problems. But I can not read Json. I'm trying to store it in the variable "maoe"
You are trying to do send a GET request to a resource that accepts only POST requests. That is why you are getting a 405 response. Change either your rest service or angular http service to have both matching request types.
I have a method in jersey servlet which consumes both MULTIPART_FORM_DATA and application/x-www-form-urlencoded Media Types, In my request I am sending some parameters along with a file in the file input stream.
Here is my method
#POST
#Path("/upload")
#Consumes({MediaType.MULTIPART_FORM_DATA,MediaType.APPLICATION_FORM_URLENCODED})
#Produces(MediaType.TEXT_PLAIN)
public String uploadFile(MultivaluedMap<String,String> requestParamsPost,#FormDataParam("file") InputStream fis,
#FormDataParam("file") FormDataContentDisposition fdcd){
//some code goes here
}
But my problem is when I start my server after making the mapping of the servlet in web.xml, I get some severe exceptions
SEVERE: Missing dependency for method public javax.ws.rs.core.Response com.package.ImportService.uploadFile(java.lang.String,java.lang.String,java.lang.String) at parameter at index 0
SEVERE: Missing dependency for method public javax.ws.rs.core.Response com.package.ImportService.uploadFile(java.lang.String,java.lang.String,java.lang.String) at parameter at index 1
SEVERE: Missing dependency for method public javax.ws.rs.core.Response com.package.ImportService.uploadFile(java.lang.String,java.lang.String,java.lang.String) at parameter at index 2
Is it somehow possible to consume two Media Types in one method at single endpoint?
Sending a file Parameter is necessary in every request?
The reason for the error is the MultivaluedMap parameter. Jersey doesn't know what to do with it. You can only have one entity type per method. In your method you are trying to accept two different body types in the request. You can't do that. I don't even know how you plan on sending that from the client.
The application/x-www-form-urlencoded data needs to be part of the multipart body. So you can do
#Consumes({MediaType.MULTIPART_FORM_DATA})
public String uploadFile(#FormDataParam("form-data") MultivaluedMap<String,String> form,
#FormDataParam("file") InputStream fis,
#FormDataParam("file") FormDataContentDisposition fdcd){
That would work. The only thing is, you need to make sure the client set the Content-Type of the form-data part to application/x-www-form-urlencoded. If they don't, then the default Content-Type for that part will be text/plain and Jersey will not be able to parse it to a MultivaluedMap.
What you can do instead is just use FormDataBodyPart as a method parameter, then explicitly set the media type. Then you can extract it to a MultivaluedMap. This way the client doesn't need to be expected to set the Content-Type for that part. Some clients don't even allow for setting individual part types.
Here's an example using Jersey Test Framework
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class MultipartTest extends JerseyTest {
#Path("test")
public static class MultiPartResource {
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response post(#FormDataParam("form-data") FormDataBodyPart bodyPart,
#FormDataParam("data") String data) {
bodyPart.setMediaType(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
MultivaluedMap<String, String> formData = bodyPart.getEntityAs(MultivaluedMap.class);
StringBuilder sb = new StringBuilder();
sb.append(data).append(";").append(formData.getFirst("key"));
return Response.ok(sb.toString()).build();
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(MultiPartResource.class)
.register(MultiPartFeature.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
#Override
public void configureClient(ClientConfig config) {
config.register(MultiPartFeature.class);
}
#Test
public void doit() {
FormDataMultiPart multiPart = new FormDataMultiPart();
multiPart.field("data", "hello");
multiPart.field("form-data", "key=world");
final Response response = target("test")
.request().post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA));
assertEquals("hello;world", response.readEntity(String.class));
}
}
If you look at the logging, you will see the request as
--Boundary_1_323823279_1458137333706
Content-Type: text/plain
Content-Disposition: form-data; name="data"
hello
--Boundary_1_323823279_1458137333706
Content-Type: text/plain
Content-Disposition: form-data; name="form-data"
key=world
--Boundary_1_323823279_1458137333706--
You can see the Content-Type for the form-data body part is text/plain, which is the default, but in the server side, we explicitly set it before Jersey parses it
public Response post(#FormDataParam("form-data") FormDataBodyPart bodyPart,
#FormDataParam("data") String data) {
bodyPart.setMediaType(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
MultivaluedMap<String, String> formData = bodyPart.getEntityAs(MultivaluedMap.class);