Spring Boot with basic authentication and cors - spring

I'm working on learning spring boot, and I have some questions about basic authentication and cors.
I created two pages and ajax to backend side.
The first page ajax username and password to backend and the method is POST.
Besides, it used basic authentication.
If its successes, the first page will redirect to the second page.
The second page will ajax to backend after the second page was loaded.
It uses GET and it will get no data except HTTP.Status.
This is my ajax function in the first page.
function login () {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
alert(btoa(username + ":" + password));
var settings = {
"async": true,
"crossDomain": true,
"url": "http://localhost:10000/login",
"method": "POST",
"headers": {
"content-type": "application/json",
"accept": "application/json",
"authorization": "Basic " + btoa(username + ":" + password),
"cache-control": "no-cache",
}
}
alert(settings);
$.ajax(settings).done(function (response) {
console.log(response);
localStorage.setItem("token", btoa(username + ":" + password));
window.location = "file:///home/cyl/SecurityTest/pages/getEmployeePage.html"
});
}
This is my ajax function in the second page.
function getData () {
alert(localStorage.getItem("token"));
var settings = {
"async": true,
"crossDomain": true,
"url": "http://localhost:10000/getAllEmployee",
"method": "GET",
"headers": {
"authorization": "Basic " + localStorage.getItem("token"),
"accept": "application/json",
"content-type": "application/json",
"cache-control": "no-cache"
}
}
$.ajax(settings).done(function (response, textStatus, xhr) {
console.log(response);
});
}
This is my RestController
#RestController
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class EmployeeController {
#CrossOrigin(origins="*", allowedHeaders = "*")
#PostMapping(path = "/login")
public ResponseEntity<String> login() {
return new ResponseEntity<String>(HttpStatus.ACCEPTED);
}
#CrossOrigin(origins="*", allowedHeaders = "*")
#GetMapping(path = "/getAllEmployee")
public ResponseEntity<String> getAllEmployee() {
//List<Employee> employeeList = this.employeeDAO.getAllEmployee();
return new ResponseEntity<String>(HttpStatus.OK);
}
}
CorsConfig
#Configuration
public class CorsConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.allowCredentials(true);
}
}
But at the second page step, I got an error
"Access to XMLHttpRequest at 'http://localhost:10000/getAllEmployee' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
I can't deal with this problem despite I search some relevant issues.
Except for this question, The way I store the authentication token in the client side is a right way?
If not, how can I do that?
Thanks!

you can use this Spring annotation if you run the same spring project on your local machine and the JS project with this tag will allow you to access the rest service
#CrossOrigin(origins = "*", maxAge = 3600)
public class controllerRest{}
regards!

Related

Getting null body in response from feign client, even though a direct request is returning an entity

I have this Feign Client in my spring boot application :
#Component
#FeignClient(value = "apiKeyManager", url = "http://localhost:8081/", configuration = FileUploadConfiguration.class)
public interface ApiKeyClient {
#RequestMapping(method = RequestMethod.POST, value = "/api/public/getAppName", consumes = "application/json", produces = "application/json")
ResponseEntity getAppName(#RequestBody AppNameRequestDto appNameRequestDto);
}
And I have this code in my service, which calls it :
AppNameRequestDto request = new AppNameRequestDto(apiKey);
ResponseEntity verification = apiKeyClient.getAppName(request);
return verification;
The actual endpoint being called by the feign client looks like this :
#PostMapping(value = "getAppName", consumes = "application/json", produces = "application/json")
public ResponseEntity getAppName(#RequestBody AppNameRequestDto appNameRequestDto){
try {
return new ResponseEntity(apiKeyManagementService.getAppName(appNameRequestDto.getApiKey()), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity("Failed to locate application by API_KEY : " + appNameRequestDto.getApiKey(), HttpStatus.NOT_FOUND);
}
}
When I run this code - I get this response :
{
"headers": {
<REMOVED FOR BREVITY>
},
"body": null,
"statusCode": "OK",
"statusCodeValue": 200
}
But when I make the call to the underlying API directly, I get the response I am expecting - an entity with an accompanies 200 status :
{
"applicationName": "MyNewFileUploadServiceApplication6"
}

Spring Boot: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/error'

Everytime I used ajax for posting, I'm getting this error but the passing of data works successfully. Some said that it is because of my return statement. I also don't have any mapping for /error. This is one of my work that causes this error.
AJAX:
$.ajax
({
type: 'post',
url: '/SaveDependent',
data:
{
dependent_id: 0,
reference_no: referenceNo,
dependent_name: dNameValue[i],
dependent_dob: dDobValue[i],
dependent_gender: dGenderValue[i],
dependent_occupation: dOccupationValue[i],
dependent_relationship: dRelationshipValue[i],
dependent_beneficiary: dBeneficiaryValue[i]
},
success: function (response)
{
alert("success");
},
});
CONTROLLER:
#RequestMapping(value= "/SaveDependent", method=RequestMethod.POST)
public String saveDependent(ClientApplicationDependent clientApplicationDependent) {
clientApplicationDependentService.saveOrUpdate(clientApplicationDependent);
return "success";
}
SERVICE:
public interface ClientApplicationDependentService {
public void saveOrUpdate(ClientApplicationDependent clientApplicationDependent);
}
SERVICE IMPL:
#Override
public void saveOrUpdate(ClientApplicationDependent clientApplicationDependent) {
clientApplicationDependentRepository.save(clientApplicationDependent);
}

CXF 3.2.2 CORS failed with "No 'Access-Control-Allow-Origin' header is present"

I was developing a Restful service using CXF + spring boot. and had problems with CORS setting
I set CORS on service definition interface (GateRs)
...
#Service
#CrossOriginResourceSharing(
allowAllOrigins = true,
allowHeaders = {
"Accept", "Accept-Charset", "Accept-Encoding", "Accept-Datetime",
"Accept-Language", "Authorization", "Content-Language", "Content-Length",
"Content-Type", "Origin", "User-Agent"},
exposeHeaders = {
"Accept", "Accept-Charset", "Accept-Encoding", "Accept-Datetime",
"Accept-Language", "Authorization", "Content-Language", "Content-Length",
"Content-Type", "Origin", "User-Agent"},
allowCredentials = true,
maxAge = 1209600 )
public interface GateRs {
#POST
#Path("/require")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#VoluntarySecure
public Res require(Req req);
...
implement interface with a class
#Component
public class Gate implements GateRs {
#Override
public Res require(Req req) {
...
attach the 'CrossOriginResourceSharingFilter' to the service bean
#Bean
public CrossOriginResourceSharingFilter cors() {
return new CrossOriginResourceSharingFilter();
}
#Bean(destroyMethod = "destroy") #DependsOn(Bus.DEFAULT_BUS_ID)
public Server jaxRsServer() {
final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
factory.setServiceBean(new Gate());
factory.setProviders(Arrays.asList(jackson(), cors()));
factory.setBus(springBus());
factory.setAddress("/Gate");
return factory.create();
}
...
the client is a mobile application based on Ionic, and emulated by Chrome browser.
the '/Gate/require' returned '404' becasue CORS failed with no "
Access-Control-Allow-Origin" header.
I looked into the detail; and found out that the preflight ('OPTIONS') actually succeed; the "POST" failed, triggered the above mentioned messages
the preflight(OPTIONS)
the POST failed; it appears that the server side had not presented 'Access-Control-Allow-Origin' header in the response message
does anyone has any idea or suggestion?
thanks
I finally solved the problem by changing the '#CrossOriginResourceSharing' as follows:
...
#CrossOriginResourceSharing(
allowAllOrigins = true,
allowCredentials = true,
maxAge = 1209600 )
public interface GateRs {
...

Upload file with JSON data in Angular5 and Spring Boot

I am stuck in getting the request at my REST Controller.
Below is my Controller method :
#RestController
#CrossOrigin(origins = "http://localhost:4200", allowedHeaders = "*")
public class UserController {
#Autowired
public UserService userService;
#PostMapping(value = "/fileUploadApi", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public #ResponseBody StatusUpload fileUpload(#RequestPart("uploadfile") MultipartFile file, #RequestPart("user") User userDto) throws Exception{
StatusUpload status= new StatusUpload();
status = userService.callUserServiceForFileRead(file, userDto);
return status;
}
In ApplicationConfig.java, I added the following :
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(500000000);
return multipartResolver;
}
Below is the code I have written for file upload at Angular5 end:
HTML:
<!-- Other form elements -->
<!-- Used PrimeNG Custom Upload Handler to get the File Object https://www.primefaces.org/primeng/#/fileupload -->
<label>Upload template </label>
<p-fileUpload (uploadHandler)="getFile($event)" auto="true" customUpload="true" accept=".xlsx,application/msexcel" previewWidth="0" [showUploadButton]="false" [showCancelButton]="false">
</p-fileUpload>
<!-- Form Submit Button -->
<button type="button" (click)="submit()">SUBMIT</button>
COMPONENT :
user: User = new User;
// Set other form element data in user object.
uploadFile: File;
getFile(event) {
this.uploadfile= event.files[0];
}
submit() {
this.userService.saveUserData(this.user,this.uploadFile);
}
SERVICE :
options = {
headers: new HttpHeaders({ 'Content-Type': '' })
};
constructor(private http: HttpClient) { }
saveUserData(user:User, uploadFile:File){
var formData: FormData = new FormData();
formData.append('user',JSON.stringify(user));
formData.append('uploadfile',uploadFile);
return this.http.post<StatusUpload>(baseUrl + "/fileUploadApi", formData, this.options);
}
When I use the above Service, it gives me no response/no Exception don't know why. The request even didn't reach my RESTController.
I read a different approach in some post & used it as below :
saveUserData(user: User, uploadFile: File) {
var formData: FormData = new FormData();
Observable.fromPromise(new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
formData.append('user', new Blob([JSON.stringify(user)],
{
type: "application/json"
}));
formData.append('uploadfile', uploadFile);
xhr.open("POST", baseUrl + "/fileUploadApi", true);
xhr.send(formData);
}));
}
With above, I get org.springframework.web.multipart.support.MissingServletRequestPartException.
Can anyone please help to get this code working. I need to use the http.post() in my Angular service, not the XMLHttpRequest.send() one.
You need to subscribe to the observable.
An HttpClient method does not begin its HTTP request until you call subscribe() on the observable returned by that method. This is true for all HttpClient methods.
Docs

Spring Controller + Ajax return String

I want to return String from Spring MVC Controller to Ajax.
It is not working as expected and gives error.
My Ajax codes for this:
function ajaxRequest(item) {
$.ajax({
type: "POST",
url: "/myPage",
data: {
item: item
},
success: function (html) {
alert(html);
},
error: function(e) {
console.log("Error:" + e);
}
});
}
My Controller:
#RequestMapping(value = "/myPage", method= RequestMethod.POST, produces="text/plain")
public #ResponseBody String myController(HttpServletRequest request) {
String myItem = request.getParameter("item");
...
return myItem + "bla bla bla";
}
Chrome console result:
POST http://localhost:8080/myPage 406 (Not Acceptable) jquery.js
Error:[object XMLHttpRequest]
What am i missing here?
When you return a String from a handler method annotated with #ResponseBody, Spring will use a StringHttpMessageConverter which sets the return content-type to text/plain. However, your request does not have an Accept header for that content-type so the Server (your Spring app) deems it unacceptable to return text/plain.
Change your ajax to add the Accept header for text/plain.
I have solved it. We can return correct values with response writer.
#RequestMapping(value = "/myPage")
public void myController(HttpServletRequest request, HttpServletResponse response) throws IOException {
String myItem = request.getParameter("item");
...
response.getWriter().println(myItem + "bla bla bla");
}
Be sure that you have Jackson dependency. Spring MVC can relies on it.

Resources