Angular 6 Http Interceptors, заголовки запросов не изменены

Я создал перехватчик, чтобы добавлять заголовок авторизации к каждому запросу, отправляемому клиентом, вот код:

import { HttpInterceptor, HttpRequest, HttpHandler, HttpHeaderResponse, HttpSentEvent, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpEvent, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
import { Injectable } from "@angular/core";

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log(localStorage.getItem('jwtToken'));
        if(localStorage.getItem('jwtToken')){
            const request = req.clone({
                setHeaders: {
                    Authorization: `bearer ${localStorage.getItem('jwtToken')}`
                }
            });
            console.log(request.headers.get("Authorization"));
            return next.handle(request);
        }
        return next.handle(req);
    }
}

Когда запрос отправляется, вызывается перехват функции, и заголовок авторизации устанавливается в соответствии со значением токена в переменной "request", как вы можете видеть там: снимок экрана консоли токена

Но заголовок авторизации не отображается в запросе, отправленном моим браузером: заголовки сетевых запросов и серверная часть не может разрешить токен.

Ты знаешь почему ?

Вот моя весенняя конфигурация:

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

public final static String AUTHORIZATION_HEADER = "Authorization";

@Autowired
UserService userService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(getProvider());
}

@Bean
public JwtTokenFilter jwtAuthenticationFilter() {
    return new JwtTokenFilter();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .csrf()
        .disable()
    .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
    .authorizeRequests()
        .antMatchers("/auth/**")
            .permitAll()
        .anyRequest()
            .authenticated();
}

@Bean
public AuthenticationProvider getProvider() {
    AppAuthProvider provider = new AppAuthProvider();
    provider.setUserDetailsService(userService);
    return provider;
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

}

CorsConfig.java

@Configuration
public class CorsConfiguration {

        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    .allowedOrigins("http://localhost:4200")
                    .allowedMethods("*")
                    .allowedHeaders("*");
                }
            };
        }

}

person Alex_Doe    schedule 22.06.2018    source источник


Ответы (1)


Ваша проблема связана с серверными службами. Из соображений безопасности по умолчанию принимаются только некоторые заголовки, остальные игнорируются.

Чтобы решить вашу проблему, вам необходимо настроить пользовательские принятые заголовки. Authorization заголовок, даже если он подобен стандарту для JWT, считается настраиваемым заголовком.

Я могу привести пример моей конфигурации Spring Security:

@Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

Обратите внимание на линию

config.addAllowedHeader("*");

Это означает, что мои службы REST принимают все возможные заголовки, отправленные клиентом. Очевидно, что это плохая конфигурация, вы должны ограничить разрешенные заголовки и другие вещи в соответствии с вашими потребностями, насколько это возможно.

Очевидно, что если вы не используете Spring Security, вам нужно найти способ сделать то же самое с языком / фреймворком yout.

Это мой SecurityConfig.java. Он немного отличается от вашего. Попробуйте это и дайте мне знать

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private WLUserDetailsService userDetailsService;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.route.authentication.path}")
    private String authenticationPath;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoderBean());
    }

    @Bean
    public PasswordEncoder passwordEncoderBean() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // we don't need CSRF because our token is invulnerable
                .csrf().disable()

                // TODO adjust CORS management
                .cors().and()

                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()

                // don't create session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()

                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated();

        // Custom JWT based security filter
        JwtAuthorizationTokenFilter authenticationTokenFilter = new JwtAuthorizationTokenFilter(userDetailsService(), jwtTokenUtil, tokenHeader);
        httpSecurity
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

//        // disable page caching
//        httpSecurity
//                .headers()
//                .frameOptions().sameOrigin()  // required to set for H2 else H2 Console will be blank.
//                .cacheControl();
    }

    @Override
    public void configure(WebSecurity web) {
        // AuthenticationTokenFilter will ignore the below paths
        web
                .ignoring()
                .antMatchers(
                        HttpMethod.POST,
                        authenticationPath
                )

                // allow anonymous resource requests
                .and()
                .ignoring()
                .antMatchers(
                        HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                );
    }


    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
//        config.addExposedHeader("Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
//                "Content-Type, Access-Control-Request-Method, Custom-Filter-Header");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

}
person firegloves    schedule 22.06.2018
comment
Спасибо за ваш ответ, я тоже использую платформу безопасности Spring для бэкэнда. Добавляю config.addAllowedHeader (*); в мою конфигурацию Cors, как вы предложили, но она все еще не работает. - person Alex_Doe; 25.06.2018
comment
Вы проверили, что исполняется? - person firegloves; 25.06.2018
comment
Да, он выполняется, но значение, которое он получает от «авторизации», равно нулю, однако оно работает, когда я отправляю запрос почтальону. - person Alex_Doe; 25.06.2018
comment
От почтальона вы не ограничены безопасностью Javascript. Отправьте мне свой весенний конфиг, пожалуйста. - person firegloves; 25.06.2018
comment
Я никогда не использовал ваш подход, я не могу ничего, кроме публикации моего кода, в надежде, что это будет полезно :) - person firegloves; 25.06.2018
comment
Я обнаружил проблему благодаря опубликованному вами коду, я забыл .cors () в методе configure. Теперь это работает! Спасибо ! - person Alex_Doe; 25.06.2018