CORS พร้อมสปริงบูตและเชิงมุม js ไม่ทำงาน


87

ฉันพยายามเรียกจุดสิ้นสุด REST บนแอปพลิเคชันหนึ่ง (แอปพลิเคชันสปริงบูต) จากอีกแอปพลิเคชัน (angularjs) แอปพลิเคชันกำลังทำงานบนโฮสต์และพอร์ตต่อไปนี้

  • แอปพลิเคชัน REST โดยใช้สปริงบูต http://localhost:8080
  • แอปพลิเคชัน HTML โดยใช้ angularjs http://localhost:50029

ฉันกำลังใช้spring-securityกับแอปพลิเคชันสปริงบูตด้วย จากแอปพลิเคชัน HTML ฉันสามารถตรวจสอบสิทธิ์กับแอปพลิเคชัน REST ได้ แต่หลังจากนั้นฉันก็ยังไม่สามารถเข้าถึงปลายทาง REST ใด ๆ ตัวอย่างเช่นฉันมีบริการ angularjs ที่กำหนดไว้ดังนี้

adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
    var s = {};
    s.isAdminLoggedIn = function(data) {
        return $http({
            method: 'GET',
            url: 'http://localhost:8080/api/admin/isloggedin',
            withCredentials: true,
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        });
    };
    s.login = function(username, password) {
        var u = 'username=' + encodeURI(username);
        var p = 'password=' + encodeURI(password);
        var r = 'remember_me=1';
        var data = u + '&' + p + '&' + r;

        return $http({
            method: 'POST',
            url: 'http://localhost:8080/login',
            data: data,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        });
    };
    return s;
}]);

ตัวควบคุม angularjs มีลักษณะดังต่อไปนี้

adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
    $scope.username = '';
    $scope.password = '';

    $scope.signIn = function() {
        AdminService.login($scope.username, $scope.password)
            .success(function(d,s) {
                if(d['success']) {
                    console.log('ok authenticated, call another REST endpoint');
                    AdminService.isAdminLoggedIn()
                        .success(function(d,s) {
                            console.log('i can access a protected REST endpoint after logging in');
                        })
                        .error(function(d, s) { 
                            console.log('huh, error checking to see if admin is logged in');
                            $scope.reset();
                        });
                } else {
                    console.log('bad credentials?');
                }
            })
            .error(function(d, s) {
                console.log('huh, error happened!');
            });
    };
}]);

เมื่อโทรไปhttp://localhost:8080/api/admin/isloggedinฉันได้รับ401 Unauthorized.

ในด้านแอปพลิเคชัน REST ฉันมีตัวกรอง CORS ที่มีลักษณะดังต่อไปนี้

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
            chain.doFilter(req, res);
        }
    }

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

การกำหนดค่าความปลอดภัยสปริงของฉันมีลักษณะดังต่อไปนี้

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private JsonAuthSuccessHandler jsonAuthSuccessHandler;

    @Autowired
    private JsonAuthFailureHandler jsonAuthFailureHandler;

    @Autowired
    private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;

    @Autowired
    private AuthenticationProvider authenticationProvider;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Value("${rememberme.key}")
    private String rememberMeKey;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
            .authorizeRequests()
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                .antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .successHandler(jsonAuthSuccessHandler)
                .failureHandler(jsonAuthFailureHandler)
                .permitAll()
                .and()
            .logout()
                .deleteCookies("remember-me", "JSESSIONID")
                .logoutSuccessHandler(jsonLogoutSuccessHandler)
                .permitAll()
                .and()
            .rememberMe()
                .userDetailsService(userDetailsService)
                .tokenRepository(persistentTokenRepository)
                .rememberMeCookieName("REMEMBER_ME")
                .rememberMeParameter("remember_me")
                .tokenValiditySeconds(1209600)
                .useSecureCookie(false)
                .key(rememberMeKey);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .authenticationProvider(authenticationProvider);
    }
}

ตัวจัดการทั้งหมดกำลังทำคือการเขียนการตอบสนอง JSON เช่น{success: true}ขึ้นอยู่กับว่าผู้ใช้ลงชื่อเข้าใช้ไม่สามารถตรวจสอบสิทธิ์หรือออกจากระบบ RestAuthenticationEntryPointดูเหมือนดังต่อไปนี้

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
            throws IOException, ServletException {
        resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }

}

มีความคิดเกี่ยวกับสิ่งที่ฉันพลาดหรือทำผิดหรือไม่?


ฉันคิดว่าคุณต้องมีการตรวจสอบสิทธิ์ด้วยเช่นโทเค็นหรืออะไรบางอย่าง คุณมีเซิร์ฟเวอร์ 2 เครื่อง คุณดูบทช่วยสอนนั้นหรือไม่? spring.io/guides/tutorials/spring-security-and-angular-js
Gokhan Oner

@GokhanOner ฉันจะดำเนินการตรวจสอบสิทธิ์ได้อย่างไร? นั่นอาจเป็นส่วนที่ขาดหายไปของปัญหานี้ นอกจากนี้ใช่ฉันได้อ่านบทแนะนำเหล่านั้นแล้วและไม่คิดว่าพวกเขาสอดคล้องกับแนวทางของฉัน สองส่วนแรกจัดการกับการรับรองความถูกต้อง Http-Basic จากนั้นส่วนที่สามจัดการกับ Redis (ฉันไม่ต้องการหรือวางแผนที่จะรับสิ่งนั้นเป็นการพึ่งพา) จากนั้นบทช่วยสอนสุดท้ายเกี่ยวAPI Gatewayกับ Spring Cloud ซึ่งฉันคิดว่าเป็น overkill .
Jane Wayne

ฉันคิดว่าคุณสามารถทำได้โดยไม่ต้องใช้ redis มันเป็นเพียงที่เก็บแคชคีย์ - ค่าเท่านั้น คุณจำเป็นต้องจัดเก็บการรับรองความถูกต้องและโทเค็น CSRF ไว้ในร้านค้าซึ่งเป็นไปได้ภายในแผนที่ทันที สิ่งสำคัญคือคีย์การตรวจสอบสิทธิ์ ดูตัวอย่าง: github.com/dsyer/spring-security-angular/tree/master/… และหน้าที่มี "เซิร์ฟเวอร์ทรัพยากร" คุณจะเห็นถั่วเพิ่มเติมที่กำหนดลำดับของตัวกรอง CORS ก็สำคัญเช่นกัน และไม้ค้ำยันบางส่วน จำเป็นต้องเปลี่ยนแปลงด้วย
Gokhan Oner

โอเคฉันทำการวิจัยอย่างรวดเร็ว สิ่งที่คุณต้องการในการกำจัด Redis คือการบรรจุถั่ว springSessionRepositoryFilter ให้ดูที่github.com/spring-projects/spring-session/blob/1.0.0.RC1/…และยังมี sessionRepository bean และใน bean นี้ แทนที่จะเป็น RedisOperationsSessionRepository คุณสามารถใช้ MapSessionRepository ซึ่งอยู่ในเซสชันฤดูใบไม้ผลิได้เช่นกัน แล้วทำตามตัวอย่าง.
Gokhan Oner

คำตอบ:


104
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SimpleCORSFilter implements Filter {

private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);

public SimpleCORSFilter() {
    log.info("SimpleCORSFilter init");
}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}

}

ไม่จำเป็นต้องกำหนดตัวกรองนี้เพิ่มเติมเพียงแค่เพิ่มคลาสนี้ ฤดูใบไม้ผลิจะถูกสแกนและเพิ่มให้คุณ SimpleCORSFilter นี่คือตัวอย่าง: spring-enable-cors


คำถามเล็กน้อย. 1) ฉันควรใส่ค่าคงที่ของสตริงที่ไหนHEADERSและX_REDIRECT_LOCATION_HEADER? 2) บรรทัดนี้request.getRequestURL());พิมพ์ผิดหรือคัดลอก / วางผิดหรือเปล่า 3) ทำไมคุณไม่ตรวจสอบOPTIONSและดำเนินการต่อโดยใช้โซ่กรอง?
Jane Wayne

2
แต่มันบล็อกไม่ให้เรียกใช้ AuthenticationEntryPoint .. โปรดชี้แนะ
Pra_A

1
ขอบคุณมากมันช่วยฉันได้อย่างยอดเยี่ยมในการต่อสู้เพื่อให้สปริงและถ่านมาทำงานร่วมกัน ไชโยเพื่อน!
Tomasz Szymanek

FindBugs ไม่ชอบการตั้งค่าพารามิเตอร์ส่วนหัวด้วย: request.getHeader("Origin")ดังที่แสดงไว้ด้านบนเนื่องจากการแยกการตอบสนอง HTTP
Glenn

3
หากมีตัวกรองอื่น ๆ ในใบสมัครของคุณกรองนี้จะต้องมีความสำคัญสูงสุดโดย annotating @Order(Ordered.HIGHEST_PRECEDENCE) กรองด้วย
Shafiul

44

ฉันเคยอยู่ในสถานการณ์ที่คล้ายกัน หลังจากทำการวิจัยและทดสอบแล้วนี่คือสิ่งที่ฉันค้นพบ:

  1. ด้วย Spring Boot วิธีที่แนะนำในการเปิดใช้ CORS ทั่วโลกคือการประกาศภายใน Spring MVC และรวมกับการ@CrossOriginกำหนดค่าแบบละเอียดเป็น:

    @Configuration
    public class CorsConfig {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                            .allowedHeaders("*");
                }
            };
        }
    }
    
  2. ตอนนี้เนื่องจากคุณใช้ Spring Security คุณจึงต้องเปิดใช้งาน CORS ที่ระดับ Spring Security ด้วยเพื่อให้สามารถใช้ประโยชน์จากการกำหนดค่าที่กำหนดไว้ที่ระดับ Spring MVC เป็น:

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()...
        }
    }
    

    นี่คือบทช่วยสอนที่ยอดเยี่ยมมากที่อธิบายการสนับสนุน CORS ใน Spring MVC framework


3
อัพมันใช้ได้กับการเปลี่ยนแปลงนี้ http .csrf () .disable () .cors () .and ()
marti_

1
@Osgux ยินดีที่ได้ฟัง :) เนื่องจากฉันใช้ JWT เพื่อการอนุญาตและพวกเขาปลอดภัย csrf ฉันไม่ได้ใส่ไว้ที่นั่น .. อย่าลืมโหวตถ้ามันช่วย :)
Yogen Rai

ใช่ฉันเพิ่ม +1 = D
marti_

@Marcel คุณได้รับปัญหาอะไร?
Yogen Rai

ไม่สามารถโหลด <ที่อยู่ส่วนที่เหลือของฉัน>: การตอบสนองต่อคำขอ preflight ไม่ผ่านการตรวจสอบการควบคุมการเข้าถึง: ไม่มีส่วนหัว "Access-Control-Allow-Origin" อยู่ในทรัพยากรที่ร้องขอ Origin ' localhost: 8090 ' จึงไม่ได้รับอนุญาตให้เข้าถึง
Marcel

22

หากคุณต้องการเปิดใช้งาน CORS โดยไม่ต้องใช้ตัวกรองหรือไม่มีไฟล์กำหนดค่าให้เพิ่ม

@CrossOrigin

ไปที่ด้านบนของตัวควบคุมของคุณและใช้งานได้


4
อะไรคือความเสี่ยงด้านความปลอดภัยโดยปฏิบัติตามแนวทางนี้?
Balaji Vignesh

ได้ผลสำหรับฉันฉันพยายามเพิ่มส่วนหัวโดยตรงเพื่อตอบสนอง แต่ไม่ได้ผลเนื่องจากไม่ได้รับการจัดการไฟล่วงหน้า ฉันคิดว่านี่ไม่ปลอดภัย แต่อาจใช้เป็นแอพภายในบางตัว
amisiuryk

ทำงานให้ฉัน โซลูชันที่มีประโยชน์สำหรับการใช้งานภายใน
Ajay Kumar

8

ในการสร้างคำตอบอื่น ๆ ข้างต้นในกรณีที่คุณมีแอปพลิเคชันบริการ Spring boot REST (ไม่ใช่ Spring MVC) ที่มีการรักษาความปลอดภัย Spring จากนั้นการเปิดใช้งาน CORS ผ่าน Spring security ก็เพียงพอแล้ว (หากคุณใช้ Spring MVC ให้ใช้WebMvcConfigurerbean ตามที่ Yogen กล่าวไว้ วิธีที่จะไปเนื่องจาก Spring security จะมอบอำนาจให้กับคำจำกัดความ CORS ที่กล่าวถึงในนั้น)

ดังนั้นคุณต้องมีการกำหนดค่าความปลอดภัยที่ทำสิ่งต่อไปนี้:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    //other http security config
    http.cors().configurationSource(corsConfigurationSource());
}

//This can be customized as required
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    List<String> allowOrigins = Arrays.asList("*");
    configuration.setAllowedOrigins(allowOrigins);
    configuration.setAllowedMethods(singletonList("*"));
    configuration.setAllowedHeaders(singletonList("*"));
    //in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

}

ลิงค์นี้มีข้อมูลเพิ่มเติมเหมือนกัน: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors

บันทึก:

  1. การเปิดใช้งาน CORS สำหรับต้นกำเนิดทั้งหมด (*) สำหรับแอปพลิเคชันที่ปรับใช้ prod อาจไม่ใช่ความคิดที่ดีเสมอไป
  2. สามารถเปิดใช้งาน CSRF ผ่านการปรับแต่ง Spring HttpSecurity ได้โดยไม่มีปัญหาใด ๆ
  3. ในกรณีที่คุณเปิดใช้งานการตรวจสอบสิทธิ์ในแอปด้วย Spring (ผ่านทางUserDetailsServiceตัวอย่าง) configuration.setAllowCredentials(true);จะต้องเพิ่ม

ผ่านการทดสอบสำหรับ Spring boot 2.0.0.RELEASE (เช่น Spring 5.0.4.RELEASE และ Spring security 5.0.3.RELEASE)


สิ่งนี้ช่วยแก้ปัญหาของฉันได้ ตั้งแต่ยังใหม่กับ Spring และ Spring Boot ฉันตระหนักว่าฉันไม่ได้สร้างด้วย Sring MVC ฉันมีไคลเอนต์ Vue.js คำตอบอื่น ๆ ดูเหมือนจะเป็นสำหรับ Spring MVC แต่คำตอบนี้เชื่อมโยงอย่างดีกับการรับรองความถูกต้องและการอนุญาตของฉัน
jaletechs

สวัสดี @jaletechs ฉันใช้ nuxtJs (เฟรมเวิร์ก vuejs) มากเกินไป แต่เมื่อพูดถึงการตั้งค่าคุกกี้มันไม่ทำงาน คุณจะใจดีพอที่จะช่วยในเรื่องนี้
KAmit

6

ฉันใช้spring boot 2.1.0และสิ่งที่ได้ผลสำหรับฉันคือทำ

A. เพิ่มการแมปคอร์โดย:

@Configuration
public class Config implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }
}

B. เพิ่มการกำหนดค่าด้านล่างให้กับ my HttpSecurityfor spring security

.cors().configurationSource(new CorsConfigurationSource() {

    @Override
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedHeaders(Collections.singletonList("*"));
        config.setAllowedMethods(Collections.singletonList("*"));
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        return config;
    }
})

นอกจากนี้ในกรณีของพร็อกซี Zuul คุณสามารถใช้แทน A และ B นี้ได้ (ใช้HttpSecurity.cors()เพื่อเปิดใช้งานใน Spring security):

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

ส่งคืน CorsFilter ใหม่ (ที่มา); ไม่ใช่ข้อผิดพลาดของตัวสร้างดังกล่าว
Aadam

@Aadam คุณใช้สปริงบูตรุ่นเดียวกับฉันหรือเปล่า?
ก.ย. GH

2.1.5 ถูกใช้งาน
Aadam

@Aadam กรุณาตรวจสอบให้แน่ใจว่าคุณกำลังใช้ CorsFilter org.springframework.web.filter.CorsFilterจาก ฉันมีปัญหาเดียวกันในขณะที่ฉันใช้มันจากแพ็คเกจ catalina โดยบังเอิญ
ก.ย. GH

5

สิ่งนี้ใช้ได้กับฉัน:

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter  {
   //...
   @Override
   protected void configure(HttpSecurity http) throws Exception {

       //...         

       http.cors().configurationSource(new CorsConfigurationSource() {

        @Override
        public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedHeaders(Collections.singletonList("*"));
            config.setAllowedMethods(Collections.singletonList("*"));
            config.addAllowedOrigin("*");
            config.setAllowCredentials(true);
            return config;
        }
      });

      //...

   }

   //...

}

แม้ว่ารหัสนี้อาจตอบคำถาม แต่การให้บริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีที่รหัสนี้ตอบคำถามช่วยเพิ่มมูลค่าในระยะยาว
Adriano Martins

1
ในกรณีที่เปิดใช้งานการรับรองความถูกต้องผ่าน Spring security จากนั้น config.setAllowCredentials (true); ต้องใส่มิฉะนั้นคำขอ CORS จะยังคงล้มเหลว
Deepak

2

สำหรับฉันสิ่งเดียวที่ได้ผล 100% เมื่อใช้การรักษาความปลอดภัยในฤดูใบไม้ผลิคือการข้ามตัวกรองและถั่วพิเศษเพิ่มเติมทั้งหมดและสิ่งที่ "เวทมนตร์" ทางอ้อมยังคงแนะนำว่าใช้ได้ผลสำหรับพวกเขา แต่ไม่ใช่สำหรับฉัน

แทนที่จะบังคับให้เขียนส่วนหัวที่คุณต้องการด้วยข้อความธรรมดาStaticHeadersWriter:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

        http
            // your security config here
            .authorizeRequests()
            .antMatchers(HttpMethod.TRACE, "/**").denyAll()
            .antMatchers("/admin/**").authenticated()
            .anyRequest().permitAll()
            .and().httpBasic()
            .and().headers().frameOptions().disable()
            .and().csrf().disable()
            .headers()
            // the headers you want here. This solved all my CORS problems! 
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization"));
    }
}

นี่เป็นวิธีที่ตรงและชัดเจนที่สุดที่ฉันพบว่าทำ หวังว่ามันจะช่วยใครบางคน


1

นี่คือสิ่งที่ได้ผลสำหรับฉัน

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

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

        http.cors();
    }

}

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
            .addMapping("/**")
            .allowedMethods("*")
            .allowedHeaders("*")
            .allowedOrigins("*")
            .allowCredentials(true);
    }

}

1

ขั้นตอนที่ 1

การใส่คำอธิบายประกอบคอนโทรลเลอร์พร้อม@CrossOriginคำอธิบายประกอบจะทำให้สามารถกำหนดค่า CORS ได้

@CrossOrigin
@RestController
public class SampleController { 
  .....
}

ขั้นตอนที่ 2

Spring มี CorsFilter อยู่แล้วแม้ว่าคุณจะสามารถลงทะเบียน CorsFilter ของคุณเองเป็น bean เพื่อกำหนดค่าของคุณเองได้ดังนี้

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins
    config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
    config.setAllowCredentials(true);
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

0

ตรวจสอบสิ่งนี้:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    ...
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
    ...
}

แม้ว่ารหัสนี้อาจตอบคำถาม แต่การให้บริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีที่รหัสนี้ตอบคำถามช่วยเพิ่มมูลค่าในระยะยาว
rollstuhlfahrer

0

การขยายคลาส WebSecurityConfigurerAdapter และการแทนที่วิธีการกำหนดค่า () ในคลาส @EnableWebSecurity ของคุณจะใช้ได้ผล: ด้านล่างนี้เป็นคลาสตัวอย่าง

@Override
protected void configure(final HttpSecurity http) throws Exception {

         http
        .csrf().disable()
        .exceptionHandling();
         http.headers().cacheControl();

        @Override
        public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
            return new CorsConfiguration().applyPermitDefaultValues();
        }
    });
   }
}

0

หาก แต่เดิมโปรแกรมของคุณไม่ใช้การรักษาความปลอดภัยแบบสปริงและไม่สามารถจ่ายค่าเปลี่ยนรหัสได้การสร้างพร็อกซีย้อนกลับอย่างง่ายสามารถทำเคล็ดลับได้ ในกรณีของฉันฉันใช้ Nginx กับการกำหนดค่าต่อไปนี้:

http {
  server {
    listen 9090;
    location / {
      if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      #
      # Custom headers and headers various browsers *should* be OK with but aren't
      #
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      #
      # Tell client that this pre-flight info is valid for 20 days
      #
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain; charset=utf-8';
      add_header 'Content-Length' 0;
      return 204;
      }
      if ($request_method = 'POST') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }
      if ($request_method = 'GET') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }

      proxy_pass http://localhost:8080;
    }
  }
}

โปรแกรมของฉันฟัง: 8080 :

REF: CORS บน Nginx


0

คำตอบนี้คัดลอกคำตอบ @abosancic แต่เพิ่มความปลอดภัยเป็นพิเศษเพื่อหลีกเลี่ยงการใช้ประโยชน์จาก CORSหลีกเลี่ยงการใช้ประโยชน์จาก

เคล็ดลับ 1: อย่าแสดงแหล่งกำเนิดขาเข้าตามที่เป็นอยู่โดยไม่ตรวจสอบรายชื่อโฮสต์ที่อนุญาตให้เข้าถึง

เคล็ดลับ 2: อนุญาตคำขอที่รับรองเฉพาะสำหรับโฮสต์ที่อนุญาตเท่านั้น

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SimpleCORSFilter implements Filter {

    private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);

    private List<String> allowedOrigins;

    public SimpleCORSFilter() {
        log.info("SimpleCORSFilter init");
        allowedOrigins = new ArrayList<>();
        allowedOrigins.add("https://mysafeorigin.com");
        allowedOrigins.add("https://itrustthissite.com");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String allowedOrigin = getOriginToAllow(request.getHeader("Origin"));

        if(allowedOrigin != null) {
            response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
        }

        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

    public String getOriginToAllow(String incomingOrigin) {
        if(allowedOrigins.contains(incomingOrigin.toLowerCase())) {
            return incomingOrigin;
        } else {
            return null;
        }
    }
}

0

ในแอป Spring Boot ของเราเราได้ตั้งค่า CorsConfigurationSource ไว้เช่นนี้

ลำดับของการเพิ่มallowedOrignsก่อนแล้วจึงตั้งค่าapplyPermitDefaultValues()ให้ Spring ตั้งค่าเริ่มต้นสำหรับส่วนหัวที่อนุญาตส่วนหัวที่เปิดเผยวิธีการที่อนุญาต ฯลฯ ดังนั้นเราจึงไม่จำเป็นต้องระบุสิ่งเหล่านั้น

    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084"));
        configuration.applyPermitDefaultValues();

        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**", configuration);
        return configurationSource;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/api/**")
                .access("@authProvider.validateApiKey(request)")
                .anyRequest().authenticated()
                .and().cors()
                .and().csrf().disable()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint);

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

0

เพียงแค่สร้างคลาสเดียวทุกอย่างจะดีด้วยสิ่งนี้:

        @Component
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public class MyCorsConfig implements Filter {

            @Override
            public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
                final HttpServletResponse response = (HttpServletResponse) res;
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
                response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
                response.setHeader("Access-Control-Max-Age", "3600");
                if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
                    response.setStatus(HttpServletResponse.SC_OK);
                } else {
                    chain.doFilter(req, res);
                }
            }

            @Override
            public void destroy() {
            }

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

0

นี่คือสิ่งที่ได้ผลสำหรับฉันเพื่อปิดการใช้งาน CORS ระหว่าง Spring boot และ React

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    /**
     * Overriding the CORS configuration to exposed required header for ussd to work
     *
     * @param registry CorsRegistry
     */

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(4800);
    }
}

ฉันต้องแก้ไขการกำหนดค่าความปลอดภัยดังต่อไปนี้:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .cors().configurationSource(new CorsConfigurationSource() {

                @Override
                public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedHeaders(Collections.singletonList("*"));
                    config.setAllowedMethods(Collections.singletonList("*"));
                    config.addAllowedOrigin("*");
                    config.setAllowCredentials(true);
                    return config;
                }
            }).and()
                    .antMatcher("/api/**")
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and().httpBasic()
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler());
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.