Spring SecurityとCors SupportでSpring Bootを使用しています。
次のコードを実行した場合
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send
結果として得られます
200
次のような間違った資格情報でテストした場合
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send
401を取得する代わりに(これは、春のセキュリティで誤った認証の標準コードです)
0
次のブラウザ通知:
GET http:// localhost:5000/api/token
XMLHttpRequestはロードできません http:// localhost:50 。要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。したがって、オリジン ' http:// localhost:30 'はアクセスを許可されていません。応答のHTTPステータスコード401。
私は、状況を処理するためにサーバー応答からの有用なhttpステータスコードを必要とするフロントエンドコードを開発しています。 0よりも有用なものが必要です。また、応答本文も空です。私の設定が間違っているのか、それがソフトウェアのバグなのかわかりません。また、それがクロム(Arch Linuxを使用)なのか春のセキュリティなのかもわかりません。
私のSpring Configは次のとおりです。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("api")
public class Controller {
@RequestMapping("token")
@CrossOrigin
Map<String, String> token(HttpSession session) {
return Collections.singletonMap("token", session.getId());
}
}
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
Curlですべてをテストすると、CORSのサポートが必要ないためだと思いますが、OPTION要求でCORSをシミュレートしようとしましたが、結果も良好でした。
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested- With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
<
* Connection #0 to Host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}
そして、間違った資格情報で:
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
<
* Connection #0 to Host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}
編集:誤解を避けるため。 1.3.3 Spring Bootを使用します。ブログの投稿はこう書いています:
CORSサポートは、今後のSpring Boot 1.3リリースで利用可能になり、1.3.0.BUILD-SNAPSHOTビルドですでに利用可能です。
Spring Bootアプリケーションで@CrossOriginアノテーションを使用したコントローラーメソッドCORS構成を使用する場合、特定の構成は必要ありません。
グローバルCORS構成は、WebMvcConfigurer BeanをカスタマイズされたaddCorsMappings(CorsRegistry)メソッドで登録することにより定義できます。
グローバルcorsサポートを有効にする次のコードを追加しました。実際にこれを試しましたが、結果は同じでした。最近、もう一度試しましたが、結果は同じです。
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
しかし、問題は承認プロセス間のリダイレクトに起因するという考えは興味深いものです。この競合を避けるために、どのようにリソースへのリダイレクトを変更できますか?
編集:
私は解決策に近づいていると思います。 Access-Control-Allow-Origin:*をすべてのリクエストに追加することにより、corsを問題なくサポートするnodejsサーバーでテストしました。
Stefan Iseleがすでに言及したように、spring securityはCORSヘッダーをリダイレクトするか、または追加しないため、リクエストが壊れているようです。そのため、Spring Securityは認証を確認している間、適切なヘッダーを追加する必要があります。
誰もそうする方法を知っていますか?
編集:
私は回避策を見つけましたが、それはいようです。私は回避策を説明するスプリングブートのgithub問題を開始しました: https://github.com/spring-projects/spring-boot/issues/5834
Spring Securityは、 このブログ投稿 で説明したSpring MVC CORSサポートを活用できるようになりました。
動作させるには、Spring Securityレベルで次のようにCORSサポートを明示的に有効にする必要があります。そうしないと、Spring MVCに到達する前にCORS対応リクエストがSpring Securityによってブロックされる場合があります。
コントローラーレベル@CrossOrigin
アノテーションを使用している場合は、Spring Security CORSサポートを有効にするだけで、Spring MVC構成を活用できます。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
CORSグローバル構成を使用する場合は、次のようにCorsConfigurationSource
Beanを宣言できます。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
このアプローチは、以前に推奨されていた フィルターベースのアプローチ に取って代わります。
Spring Securityドキュメントの dedicated CORSセクション で詳細を確認できます。
JDK 8+を使用する場合、1行のラムダソリューションがあります。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
Spring Securityを使用している場合、次を実行して、CORS要求が最初に処理されるようにすることができます。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors().and()
...
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
詳細については、 Spring 4.2.x CORS を参照してください。
WithoutSpring Securityこれは動作します:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS");
}
};
}
クロスオリジン保護はブラウザの機能です。あなたが推測したように、カールはCORSを気にしません。カールが成功するのに、ブラウザーのリクエストは成功しないのはこのためです。
間違った資格情報でブラウザリクエストを送信すると、Springはクライアントをログインページに転送しようとします。 (ログインページから)この応答にはヘッダー 'Access-Control-Allow-Origin'が含まれておらず、ブラウザーは説明どおりに反応します。
このログインレスポンスにhaederを含めるためにspringを作成する必要があります。エラーページなど、他のレスポンス用にすることもできます。
これは次のように実行できます。
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
これは cors-support-in-spring-framework からコピーされます
私はすべてのリソースにCORSマッピングを追加することから始めます:
registry.addMapping("/**")
また、すべてのメソッドヘッダーを許可します。正常に機能すると、必要な最小値まで再度削減することができます。
CORS設定はリリース4.2で変更されることに注意してください。
これで問題が解決しない場合は、失敗したajaxリクエストから取得した応答を投稿してください。
Corsはお尻の痛みになる場合がありますが、この単純なコードではCorsのみです!!!!指定されたメソッドへ
@CrossOrigin(origins="*")// in this line add your url and thats is all for spring boot side
@GetMapping("/some")
public String index() {
return "pawned cors!!!!";
}
春のブーツ2.0.2の魅力のように
Spring-Boot、Spring-Security、およびJavaベースの構成の簡単なソリューションを見つけました。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
プロパティ設定用
# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.
この問題を次の方法で解決しました: `
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers","Access-Control-Allow-Origin","Access-Control-Request-Method", "Access-Control-Request-Headers","Origin","Cache-Control", "Content-Type", "Authorization"));
configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
`
この問題を次の方法で解決しました。
@Configuration
public class CORSFilter extends CorsFilter {
public CORSFilter(CorsConfigurationSource source) {
super((CorsConfigurationSource) source);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Headers",
"Access-Control-Allow-Origin, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
if (response.getHeader("Access-Control-Allow-Origin") == null)
response.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, response);
}
}
そして:
@Configuration
public class RestConfig {
@Bean
public CORSFilter corsFilter() {
CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedMethod(HttpMethod.DELETE);
config.addAllowedMethod(HttpMethod.GET);
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.PUT);
config.addAllowedMethod(HttpMethod.POST);
((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", config);
return new CORSFilter(source);
}
}
サーバーの状態を返す問題に同じ問題がありました。アプリケーションは複数のサーバーにデプロイされます。だから私が見つけた最も簡単なのは追加することです
@CrossOrigin(origins = "*")
@RequestMapping(value="/schedulerActive")
public String isSchedulerActive(){
//code goes here
}
この方法は安全ではありませんが、allowCredentials
を追加できます。
Javascript CORSから発生するエラーをよく検索した結果、このケースで見つけた唯一のエレガントなソリューションは、Spring独自のクラスorg.springframework.web.cors.CorsConfiguration.CorsConfiguration()のcorsを構成することでした。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
Axios、Spring Boot、およびSpring Securityの認証に大きな問題がありました。
Spring Bootのバージョンと使用しているSpring Securityに注意してください。
Spring Boot:1.5.10 Spring:4.3.14 Spring Security 4.2.4
注釈ベースのJava構成を使用してこの問題を解決するために、次のクラスを作成しました。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("youruser").password("yourpassword")
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().
authorizeRequests()
.requestMatchers(CorsUtils:: isPreFlightRequest).permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.realmName("Biometrix");
http.csrf().disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization"));
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Axiosの主な落とし穴の1つは、APIで認証が必要な場合、OPTIONSリクエストでAuthorizationヘッダーを送信することです。許可されたヘッダー構成設定にAuthorizationを含めない場合、OPTIONS要求(別名PreFlight要求)は失敗し、Axiosはエラーを報告します。
簡単で適切に配置されたいくつかの設定でわかるように、SpringBootでのCORS設定は非常に簡単です。
Kotlinソリューション
...
http.cors().configurationSource {
CorsConfiguration().applyPermitDefaultValues()
}
...