[解決済み] Spring-bootとangularjsのCORSが機能しない。
2023-01-29 12:30:44
質問
あるアプリケーション(spring-bootアプリケーション)のRESTエンドポイントを別のアプリケーション(angularjs)から呼び出そうとしています。アプリケーションは次のホストとポートで実行されています。
-
REST アプリケーション、spring boot を使用します。
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 { }
}
私のspring securityの設定は以下のような感じです。
@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}
のような 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");
}
}
何が足りないのか、何が間違っているのか、何かアイデアはありませんか?
どのように解決するのですか?
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() {
}
}
このクラスを追加するだけで、フィルタを定義する必要はありません。Springがスキャンして追加してくれます。SimpleCORSFilterです。 以下はその例です。 spring-enable-cors
関連
-
[解決済み] AngularJs ReferenceError: $http is not defined
-
[解決済み] 'ApplicationSignInManager' が見つからない(ASP.NET MVC)
-
[解決済み] AngularJSの「href」と「ng-href」の違いについて
-
[解決済み] md-selectでデフォルト値を設定する方法
-
[解決済み] AngularJSのリソースプロミス
-
[解決済み] AngularJS: ngRouteが動作しない。
-
[解決済み] AngularJSで$scope.$watchと$scope.$applyを使用するにはどうすればよいですか?
-
[解決済み] Spring Bootアプリケーションにポートを設定する方法
-
[解決済み] AngularJSのng-repeatでキーと値を反復処理する方法は?
-
[解決済み】AngularJSのディレクティブスコープにおける「@」と「=」の違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] `ui-router` $stateParams vs. $state.params
-
[解決済み】angularのonLoadとng-initの違いについて
-
[解決済み] angularのpostリクエストでpreflightのレスポンスがHTTPステータスコード403で不正になる。
-
[解決済み] select 要素のデフォルト値を設定するための ng-option の使用方法
-
[解決済み] data-ng-file-selectが動作しないのはなぜですか?
-
[解決済み] 誰かangularjsの$qサービスの使用について説明してください。[重複しています]。
-
[解決済み] Angular JSによるシンプルなポップアップ
-
[解決済み] angular.serviceとangular.factoryの比較
-
[解決済み] 条件に応じて特定のルートにリダイレクトする機能
-
[解決済み] Spring CORS 'Access-Control-Allow-Origin' ヘッダが存在しない。