I use Angular2, Angular-cli, Spring Boot 1.4.0 and jwt. When I sign in my Angular2 client I can not get jwt token.
My security config is:
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // disable csrf for our requests.
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/user/signup").permitAll()
.antMatchers(HttpMethod.POST, "/api/user/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/api/user/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
.permitAll().and().csrf().disable();
}
}
My TokenAuthenticationService is :
public class TokenAuthenticationService {
private final long EXPIRATIONTIME = 1000 * 60 * 60 * 24 * 10; // 10 days
private final String secret = "ThisIsASecret";
private final String tokenPrefix = "Bearer";
private final String headerString = "Authorization";
public void addAuthentication(HttpServletResponse response, String username)
{
// We generate a token now.
String JWT = Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
response.addHeader("Access-Control-Allow-Origin", "*");
response.setHeader(headerString, tokenPrefix + " "+ JWT);
response.getHeaderNames().stream()
.forEach(System.out::println);
}
}
When I send sign in request with postman, I recieve response like this:
But I send sign in request my Angular2 application I can not recieve response header named "Authorization" custom header. My response object is like this:
But I look browser console I see my costum header "Authorization".
My Angular2 code is:
@Injectable()
export class LoginService {
private authEvents: Subject<AuthEvent>;
private cred: AccountCredentials;
constructor(private http: JsonHttpService ){
this.authEvents = new Subject<AuthEvent>();
this.cred = new AccountCredentials();
}
login(email: string, password: string) {
this.cred.password = password;
this.cred.username = email;
return this.http.post('http://localhost:9090/api/user/login', this.cred)
.do((resp: Response) => {
localStorage.setItem('jwt', resp.headers.get('Authorization'));
this.authEvents.next(new DidLogin());
});
}
logout(): void {
localStorage.removeItem('jwt');
this.authEvents.next(new DidLogout());
}
isSignedIn(): boolean {
return localStorage.getItem('jwt') !== null;
}
}
export class DidLogin {
}
export class DidLogout {
}
export type AuthEvent = DidLogin | DidLogout;
And My JsonHttpService is:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import {
Http,
RequestOptionsArgs,
RequestOptions,
Response,
Headers
} from '@angular/http';
const mergeAuthToken = (options: RequestOptionsArgs = {}) => {
let newOptions = new RequestOptions({}).merge(options);
let newHeaders = new Headers(newOptions.headers);
const jwt = localStorage.getItem('jwt');
if (jwt && jwt !== 'null') {
newHeaders.set('Authorization', jwt);
}
newHeaders.set('content-type', 'application/x-www-form-urlencoded; charset=utf-8');
// newHeaders.set('Access-Control-Allow-Origin', '*');
newOptions.headers = newHeaders;
return newOptions;
};
@Injectable()
export class JsonHttpService {
constructor(private http: Http) { }
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.http.get(url, mergeAuthToken(options));
}
post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
return this.http.post(url, body, mergeAuthToken(options));
}
put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
return this.http.put(url, body, mergeAuthToken(options));
}
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.http.delete(url, mergeAuthToken(options));
}
patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
return this.http.patch(url, body, mergeAuthToken(options));
}
head(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.http.head(url, mergeAuthToken(options));
}
}
So why I can not recieve my jwt token and add my browser localStorage?
The browser does not expose custom headers to the app by default.
You will need the following header in your Backend Cors config
'Access-Control-Expose-Headers' 'Authorization';
Note that even if the headers are present in the dev console your app can't read them if they are not exposed by you server application.