Reputation: 12191
I am trying to send token information back to the server over http.post()
. If I remove the options from it it sends a POST but if I add them back on it sends OPTIONS which is rejected from the server code. I tried removing the "withCredentials" as well.
export class EntityService {
public entity: EntityModel;
private options: RequestOptions;
constructor( @Inject(Http) private http: Http, @Inject(AuthenticationService) authService) {
let headers = new Headers({ 'X-Authorization': 'Bearer ' + authService.token});
this.options = new RequestOptions({ headers: headers, withCredentials: true });
}
public store(entity: EntityModel): Observable<string> {
var request;
if (!entity.uuid) {
request = this.http.post("http://localhost:8080/api/entity", JSON.stringify(entity), this.options);
}
else {
request = this.http.put("http://localhost:8080/api/entity", JSON.stringify(fact), this.options);
}
return request.map((res: Response) => res.text());
}
}
My authentication service looks like this:
import { Injectable, Inject } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map'
//http://jasonwatmore.com/post/2016/08/16/angular-2-jwt-authentication-example-tutorial
@Injectable()
export class AuthenticationService {
public token: string;
constructor(@Inject(Http) private http: Http) {
// set token if saved in local storage
var currentUser = JSON.parse(localStorage.getItem('currentUser'));
this.token = currentUser && currentUser.token;
}
login(username: string, password: string): Observable<boolean> {;
console.log("login...");
return this.http.post('http://localhost:8080/api/auth/login', JSON.stringify({ username: username, password: password }))
.map((response: Response) => {
// login successful if there's a jwt token in the response
let token = response.json() && response.json().token;
if (token) {
// set token property
this.token = token;
// store username and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));
// return true to indicate successful login
return true;
} else {
// return false to indicate failed login
return false;
}
});
}
logout(): void {
// clear token remove user from local storage to log user out
this.token = null;
localStorage.removeItem('currentUser');
}
}
Here is my Spring configuration:
@SpringBootApplication
public class SpringBootApp extends WebMvcConfigurerAdapter {
private boolean workOffline = true;
private boolean setupSchema = false;
private IGraphService graphService;
private DbC conf;
@Autowired
public SpringBootApp(IGraphService graphService, DbC conf)
{
this.graphService = graphService;
this.conf = conf;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootApp.class, args);
}
@Bean
public Filter caseInsensitiveRequestFilter() {
return new CaseInsensitiveRequestFilter();
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "PUT", "POST", "DELETE","OPTIONS");
}
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
I really don't know what to do since I am following what is being said in Angular2 OPTIONS method sent when asking for http.GET and this is not a preflight request. I had this issue earlier with the wrong content-type.
Upvotes: 0
Views: 2533
Reputation: 12191
The actual fix was due to two reasons: improper CORS implementation - for more please have a look here: Spring 4/5 global CORS configuration doesn't work giving `No 'Access-Control-Allow-Origin' header is present on the requested resource`
Then when I was POSTing after the login I was getting error 415 Unsupported Media Type
. After following the instructions here: POST JSON fails with 415 Unsupported media type, Spring 3 mvc
I added Content-Type
and Accept
header on my request and it fixed the problem. It seems that Content-Type
is what was actually needed.
export class EntityService {
public entity: EntityModel;
private options: RequestOptions;
constructor( @Inject(Http) private http: Http, @Inject(AuthenticationService) authService) {
let headers = new Headers({
'X-Authorization': 'Bearer ' + authService.token,
'Content-Type': 'application/json'
});
this.options = new RequestOptions({ headers: headers, withCredentials: true });
}
public store(entity: EntityModel): Observable<string> {
var request;
if (!entity.uuid) {
request = this.http.post("http://localhost:8080/api/entity", JSON.stringify(entity), this.options);
}
else {
request = this.http.put("http://localhost:8080/api/entity", JSON.stringify(fact), this.options);
}
return request.map((res: Response) => res.text());
}
}
Upvotes: 2
Reputation: 1961
Using http post like this
import { Http, Headers, Response, Request } from '@angular/http';
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('X-Authorization', this.token);
headers.append('Authorization', 'Bearer ' + jwtToken);
return this.http.post(url, data, {headers})
.map(res => { console.log(res) })
.catch(err => { console.log(err) } );
Note this example returns an Observable that you can subscribe to. Also my example
Upvotes: 0
Reputation: 657871
The OPTIONS
request is made by the browser alone. Angular is not involved at all.
"and this is not a preflight request." - it definitely is.
You need to configure your server to respond properly to the OPTIONS
request or ensure that the Angular application is loaded from the same server (also same port) as where you make the request to.
Upvotes: 2