I have REST API in Spring as Backend and Angular 2 as Frontend.
I call login URL. When response is 201 all its fine, but when I send 401 / 403 I have an error.
XMLHttpRequest cannot load http://localhost:8888/emot/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 401.
Before i had this error in all request so I changed my call method in Client :
authenticate(login: string, password: string) {
let headers = this.createBasicHeaders();
this.createAuthorizationHeader(headers, login, password);
const options = new RequestOptions({headers: headers});
console.log(this.http.post(this.restApi + "/emot/login", '{}', options)
.map(this.extractData)
.toPromise()
.catch(this.handleError));
}
createAuthorizationHeader(headers: Headers, login: string, password: string) {
headers.append('Authorization', 'Basic ' +
btoa(login + ':' + password));
}
createBasicHeaders(): Headers {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
// Website you wish to allow to connect
headers.append('Access-Control-Allow-Origin', this.restApi);
// Request methods you wish to allow
headers.append('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
headers.append('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
headers.append('Access-Control-Allow-Credentials', 'true');
return headers;
}
private extractData(res: Response) {
const body = res.json();
console.log("GOOD");
return body.data || {};
}
private handleError(error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
}
else {
errMsg = error.message ? error.message : error.toString();
}
return Observable.throw(errMsg);
}
My Server Controller :
@RestController
@ComponentScan("xxxx")
@RequestMapping("/xxx")
@CrossOrigin(origins = "*")
public class RootRequestDispatcher {
@Autowired
OperatorFacade operatorFacade;
@RequestMapping(value = "login", method = RequestMethod.POST)
public ResponseEntity<OperatorDTO> logon(Authentication auth) {
System.out.println(auth);
OperatorDTO operator = operatorFacade.findOperatorByLogin(auth.getName());
return new ResponseEntity<OperatorDTO>(operator, HttpStatus.OK);
}
}
And the response sended when Operator Cretentials are NOT OK :
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.addHeader(SecurityProperties.HEADER_NAME_REALM, SecurityProperties.HEADER_VALUE_REALM + getRealmName());
authException.printStackTrace();
System.out.println("TESTING ERROR");
ObjectMapper mapper = new ObjectMapper();
PrintWriter writer = response.getWriter();
writer.println(mapper.writeValueAsString(new ExceptionBean(Causes.ANOTHER_CAUSE)));
}
I found myself solution.
For this problem, it is needed to override AccessDeniedHandler
bean. And not like I did it in previous post.
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AccessDeniedException e) throws IOException,
ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.addHeader(SecurityPathProperties.HEADER_NAME_REALM,
SecurityPathProperties.HEADER_VALUE_REALM + SecurityPathProperties.REALM);
ObjectMapper mapper = new ObjectMapper();
PrintWriter writer = httpServletResponse.getWriter();
writer.println(mapper.writeValueAsString(new ExceptionBean(ExceptionCauses.NOT_FOUND_USER)));
}
}