2015-08-31 5 views
32

मैं एक आवेदन (वसंत-बूट एप्लिकेशन) पर एक दूसरे (कोणीय) से आरईएसटी एंडपॉइंट्स को कॉल करने का प्रयास कर रहा हूं। एप्लिकेशन निम्न होस्ट और बंदरगाहों पर चल रहे हैं।वसंत-बूट और कोणीय के साथ सीओआरएस काम नहीं कर रहे

  • बाकी आवेदन, वसंत बूट का उपयोग कर, http://localhost:8080
  • एचटीएमएल आवेदन, AngularJS का उपयोग कर, http://localhost:50029

मैं भी वसंत-बूट आवेदन के साथ spring-security उपयोग कर रहा हूँ। एचटीएमएल एप्लिकेशन से, मैं आरईएसटी एप्लीकेशन को प्रमाणित कर सकता हूं, लेकिन उसके बाद, मैं अभी भी किसी भी आरईएसटी एंडपॉइंट तक नहीं पहुंच सकता। उदाहरण के लिए, मेरे पास निम्नानुसार परिभाषित एंजुलरज सेवा है।

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; 
}]); 

कोणीय नियंत्रक निम्न जैसा दिखता है।

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 मिलता है।

आरईएसटी आवेदन पक्ष पर, मेरे पास एक कॉरस फ़िल्टर है जो निम्न जैसा दिखता है।

@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); 
    } 
} 

सभी संचालकों कर रही हो {success: true} के आधार पर यदि उपयोगकर्ता में लॉग इन, प्रमाणित करने के लिए विफल रहा है, या लॉग आउट की तरह एक JSON प्रतिक्रिया बाहर लिख रहे हैं। 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"); 
    } 

} 

क्या मैं याद कर रहा हूं या गलत कर रहा हूं पर कोई विचार?

+0

मैं तुम्हें एक टोकन या कुछ और की तरह के रूप में अच्छी प्रमाणीकरण ले जाने के लिए, की जरूरत है लगता है। आपके पास 2 सर्वर हैं। क्या आपने उस ट्यूटोरियल को देखा था? Https: //spring.io/guides/tutorials/spring-security-and-angular-js/ –

+0

@GokhanOner मैं प्रमाणीकरण कैसे ले सकता हूं? शायद इस समस्या के लिए गायब टुकड़ा है। इसके अलावा, हाँ, मैं उन ट्यूटोरियल्स के माध्यम से गया था और नहीं सोचा था कि वे मेरे दृष्टिकोण के साथ गठबंधन थे। पहले दो हिस्सों में एचटीपी-बेसिक प्रमाणीकरण के साथ निपटाया गया, फिर तीसरा हिस्सा रेडिस (मैं निर्भरता के रूप में इसे प्राप्त करने की योजना नहीं बनाना चाहता था) के साथ निपटाया था, और फिर अंतिम ट्यूटोरियल वसंत बादल के साथ 'एपीआई गेटवे' के बारे में था, जिसे मैं सोचा एक ओवरकिल था। –

+0

मुझे लगता है कि आप इसे रेडिस के बिना कर सकते हैं, यह सिर्फ एक महत्वपूर्ण मूल्य कैश स्टोर है। आपको फ्लाई पर मानचित्र के अंदर संभवतः स्टोर पर प्रमाणीकरण और सीएसआरएफ टोकन स्टोर करने की आवश्यकता है। यहां महत्वपूर्ण बात प्रमाणीकरण कुंजी है। उदाहरण देखें: https: //github.com/dsyer/spring-security-angular/tree/master/spring- सत्र और "संसाधन सर्वर" वाला पृष्ठ। आप कुछ अतिरिक्त बीन्स परिभाषित करेंगे, सीओआरएस फिल्टर का क्रम भी महत्वपूर्ण है। और कुछ प्रोप। परिवर्तन भी आवश्यक है। –

उत्तर

56
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

+0

कुछ प्रश्न। 1) मुझे स्ट्रिंग स्थिरांक 'हेडरर्स' और 'X_REDIRECT_LOCATION_HEADER' कहां रखा जाना चाहिए? 2) लाइन 'request.getRequestURL()) है; 'एक टाइपो या कॉपी/पेस्ट गलती? 3) आप 'विकल्प' की जांच क्यों नहीं करते हैं और केवल फ़िल्टर श्रृंखला के साथ जारी रखते हैं? –

+2

लेकिन यह प्रमाणीकरण एंटरपॉइंट निष्पादित करने के लिए ब्लॉक करता है .. कृपया – Prateek

+1

का मार्गदर्शन करें, आपको बहुत धन्यवाद, इससे मुझे वसंत और एम्बर को मिलकर काम करने के लिए अपने संघर्ष में बहुत ही मदद मिली। चीयर्स दोस्त! –

7

मैं इसी तरह की स्थिति में था। अनुसंधान और परीक्षण करने के बाद, यहाँ मेरी निष्कर्ष है:

  1. स्प्रिंग बूट, सक्षम करने के लिए वैश्विक CORS वसंत 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. @EnableWebSecurity 
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 
    
        @Override 
        protected void configure(HttpSecurity http) throws Exception { 
         http.cors().and()... 
        } 
    } 
    
    :
  3. अब, जब से तुम स्प्रिंग सुरक्षा का उपयोग कर रहे हैं, तो आप स्प्रिंग सुरक्षा के स्तर पर CORS सक्षम करने के लिए और साथ ही यह विन्यास के रूप में वसंत MVC स्तर पर परिभाषित लाभ उठाने के लिए अनुमति देने के लिए है 10

    Here स्प्रिंग एमवीसी ढांचे में सीओआरएस समर्थन समझाते हुए बहुत ही उत्कृष्ट ट्यूटोरियल है।

+0

यह मेरे लिए काम नहीं करता है :( – Osgux

+0

@Osgux क्या त्रुटि मिल रहा है ?? –

+0

अप यह इस परिवर्तन http .csrf (साथ काम करता है) .disable() .cors() .और() – Osgux

0

जांच इस एक:

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

हालांकि यह कोड प्रश्न का उत्तर दे सकता है, इस सवाल का जवाब देने के तरीके के बारे में अतिरिक्त संदर्भ प्रदान करना और/या कैसे यह दीर्घकालिक मूल्य में सुधार करता है। – rollstuhlfahrer

संबंधित मुद्दे