Angular2 Spring Boot JWT 缺少响应标头
Posted
技术标签:
【中文标题】Angular2 Spring Boot JWT 缺少响应标头【英文标题】:Angular2 Spring Boot JWT missing Response Header 【发布时间】:2017-05-26 02:57:06 【问题描述】:我使用 Angular2、Angular-cli、Spring Boot 1.4.0 和 jwt。当我登录 Angular2 客户端时,我无法获得 jwt 令牌。
我的安全配置是:
@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();
我的 TokenAuthenticationService 是:
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);
当我通过邮递员发送登录请求时,我收到如下响应:
但我发送登录请求我的 Angular2 应用程序我无法收到名为“授权”自定义标头的响应标头。我的响应对象是这样的:
但我看浏览器控制台我看到我的服装标题“授权”。
我的 Angular2 代码是:
@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;
而我的 JsonHttpService 是:
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));
那么为什么我无法收到我的 jwt 令牌并添加我的浏览器 localStorage?
【问题讨论】:
【参考方案1】:默认情况下,浏览器不会向应用公开自定义标头。
您的后端 Cors 配置中需要以下标头
'Access-Control-Expose-Headers' 'Authorization';
请注意,即使开发控制台中存在标头,如果您的服务器应用程序没有公开它们,您的应用程序也无法读取它们。
【讨论】:
【参考方案2】:您是否在不同的端口上运行 Angular2 应用程序和 springboot?如果是这样,您是否在 springboot 应用程序中启用了 CORS?
将withCredentials: true
添加到您的 Angualr2 帖子标题
this.http.post('http://localhost:9090/api/user/login',
withCredentials: true ,
this.cred)
如需更多 springboot JWT 与 Angular 配合使用,请查看Springboot JWT Starter
【讨论】:
【参考方案3】:解决您的问题的最佳方法是在您的应用程序中添加 cors 配置,如此处所述https://spring.io/blog/2015/06/08/cors-support-in-spring-framework。 你也可以这样做:
@Configuration
public class RestConfigs
@Bean
public CorsFilter corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addExposedHeader(MyUtils.AUTHENTICATION); //Header String
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
【讨论】:
【参考方案4】:我在 Angular 6 上遇到了类似的问题,几天都找不到解决方案。经过谷歌搜索、沮丧、思考和谁知道我找到了答案:)
最后我不得不切换到纯 javascript,这个解决方案对我有用:
http.open('POST', url, true);
http.setRequestHeader('Content-type', 'application/json');
http.setRequestHeader('Accept', 'application/json, text/plain, */*');
http.onreadystatechange = function()
if (http.readyState == 4 && http.status == 200)
console.log('xhr:', http.getAllResponseHeaders());
http.send(params);
http.getAllResponseHeaders() 返回所有类似于 Web 浏览器中的标头。 希望这对您也有帮助。
我在 https://www.html5rocks.com/en/tutorials/cors/ 上找到了关于 CORS 的写得很好的帖子,这可能会引起麻烦
正如@evans-m 所说,标题必须暴露。
我仍然不确定是 Angular、浏览器还是 Spring 的问题?!
【讨论】:
以上是关于Angular2 Spring Boot JWT 缺少响应标头的主要内容,如果未能解决你的问题,请参考以下文章
带有 Spring Boot 和 Spring Security 的 Angular2