【问题标题】:Angular2 Spring Boot JWT missing Response HeaderAngular2 Spring Boot JWT 缺少响应标头
【发布时间】: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?

【问题讨论】:

    标签: angular spring-boot jwt angular-cli angular2-jwt


    【解决方案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 的问题?!​​

          【讨论】:

            猜你喜欢
            • 2016-05-09
            • 2017-07-01
            • 2017-07-29
            • 2019-05-22
            • 2016-03-08
            • 2021-08-21
            • 2018-12-31
            • 2021-01-07
            • 2019-02-25
            相关资源
            最近更新 更多