【问题标题】:Angular 6 Http Interceptors, request headers not modifiedAngular 6 Http拦截器,请求标头未修改
【发布时间】:2018-12-02 01:57:05
【问题描述】:

我创建了一个拦截器,为客户端发送的每个请求添加一个授权标头,代码如下:

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”中的令牌值正确设置,如您所见: token console screenshot

但我的浏览器发送的请求中没有出现授权标头:network request headers,并且后端无法解析令牌。

你知道为什么吗?

这是我的弹簧配置:

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("*");
                }
            };
        }

}

【问题讨论】:

    标签: spring spring-security angular6 angular-http-interceptors


    【解决方案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,您需要找到使用您的语言/框架做同样事情的方法。

    这是我的 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);
        }
    
    }
    

    【讨论】:

    • 感谢您的回复,我也在使用 Spring 安全框架作为后端。我添加“config.addAllowedHeader("*");"按照你的建议到我的 Cors 配置,但它仍然无法正常工作。
    • 你检查过执行了吗?
    • 是的,它被执行了,但是它从“授权”获得的值为空,但是当我用邮递员发送请求时它可以工作。
    • 来自邮递员,您不受 Javascript 安全性的限制。请把你的 spring 配置发给我。
    • 感谢您发布的代码,我发现了问题,我在“配置”方法中忘记了“.cors()”。现在它起作用了!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多