如何在Spring MVC中为错误响应启用CORS?

Pet*_*ter 5 spring spring-mvc cors oauth-2.0 angular

我正在开发将Spring MVC用于后端并将Angular5用于前端的应用程序。我一直沉迷于Auth2安全层(包括跨域资源共享)的实现。我的CORS过滤器实现如下所示:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter("/*")
public class WebSecurityCorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");


        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) {
            res.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(request, res);
        }

    }
    @Override
    public void destroy() {
    }
}
Run Code Online (Sandbox Code Playgroud)

我几乎可以正常工作,我能够获取access_token并使用它从ResourcesServer获取受保护的数据:

{“ access_token”:“ 4fcef1f8-4306-4047-9d4d-1c3cf74ecc44”,“ token_type”:“ bearer”,“ refresh_token”:“ 397016eb-dfb0-4944-a2e0-50c3bd07c250”,“ expires_in”:29,“ scope” :“读写信任”}

浏览器控制台屏幕截图

当我尝试使用过期的令牌处理请求时,问题就开始了。在这种情况下,我无法通过Angular捕获正确的ErrorResponeCode。而不是401,我Angular HttpClient收到了状态为0的“未知错误”。

看起来问题出在CORS策略上,其中ErrorResponse不包括必需的标头,如Access-Control-Allow-Origin(...)

无法加载http:// localhost:8030 / api / xxxx:请求的资源上没有“ Access-Control-Allow-Origin”标头。因此,不允许访问源' http:// localhost:8070 '。响应的HTTP状态码为401。

ErrorResponse标头-截图

我已经搜索了如何在Spring MVC中为ErorrResponse(InvalidTokenException等)启用CORS。我尝试了多种方法:accessDeniedHandler和setExceptionTranslator,但是没有成功。我真的很努力地自己寻找解决方案,但是我是Spring的初学者。我不确定这是否可能。

角度(更新)

@hrdkisback,这不是角度问题,无论如何这是我的代码:

@Injectable()

export class HttpInterceptorService implements HttpInterceptor {


    addToken(req: HttpRequest<any>, oauthService: AuthenticationService): HttpRequest<any> {

        if(oauthService.isTokenExist()){

            return req.clone({ setHeaders: { Authorization: 'Bearer ' + oauthService.getAccessToken() }})
        }

        return req;
    }


    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {

        let oauthService = this.inj.get(AuthenticationService);

        return next.handle(this.addToken(req,oauthService))

        .do((event: HttpEvent<any>) => {

            if (event instanceof HttpResponse) {

                // process successful responses here

            }
        }, (error: any) => { 

            if (error instanceof HttpErrorResponse) {

                // Error 

                console.log(error);
            }
        });

    }
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ter 2

在 ResourcesServer 配置级别添加 CORS 过滤器后,问题得到解决,如下所示:

对我有用的正确配置!

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {


    @Override
        public void configure(HttpSecurity http) throws Exception {

            http
            .addFilterAfter(new WebSecurityCorsFilter(), CsrfFilter.class)
            ...
        }
   ....
}
Run Code Online (Sandbox Code Playgroud)

在我之前的配置中,我以相同的方式添加了过滤器,但在 MVC 安全配置的顶层,这是我的问题的根源:

导致我的问题的先前配置

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



    @Override
            public void configure(HttpSecurity http) throws Exception {

                http
                .addFilterAfter(new WebSecurityCorsFilter(), CsrfFilter.class)
                ...
            }
       ....
    }
Run Code Online (Sandbox Code Playgroud)