Я впервые разрабатываю архитектуру клиент-сервер, и у меня возникли некоторые проблемы с настройкой сервера для приема CORS.
Я много читал, искал и тестировал, но я не могу заставить его работать в моей системе, я не знаю, что не так.
Я разработал клиент в Angular и веб-сервис в Spring Boot 2.0.4 с безопасностью Oauth2. На сервере работает Apache, который принимает запросы только от порта 443 для обслуживания Интернета и перенаправляет запросы через порт 8443 на веб-службу, развернутую в Tomcat 8.5, которая прослушивает порт 8081.
<VirtualHost _default_:8443>
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/
DocumentRoot /var/www/html
...
Изменения, которые я сделал в конфигурации Apache
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "authorization"
</IfModule>
SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private ClientDetailsService clientDetailsService;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService)
.passwordEncoder(encoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
//@f:off
http.cors()
.and()
.csrf()
.disable()
.anonymous()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
//@f:on
}
@Override
public void configure(WebSecurity web) throws Exception
{
super.configure(web);
web.ignoring()
.antMatchers("/v1/user/save")
.antMatchers("/v1/user/existsEMail")
.antMatchers("/v1/userAccess/existsUsername");
web.ignoring()
.antMatchers(HttpMethod.OPTIONS,"/**");
}
@Bean
public TokenStore tokenStore()
{
return new InMemoryTokenStore();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore)
{
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore)
{
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public BCryptPasswordEncoder encoder()
{
BytesKeyGenerator keyGenerator = KeyGenerators.secureRandom();
SecureRandom random = new SecureRandom(keyGenerator.generateKey());
return new BCryptPasswordEncoder(10, random);
}
@Bean
CorsConfigurationSource corsConfigurationSource()
{
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList(
HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name()));
config.setAllowCredentials(true);
config.combine(config.applyPermitDefaultValues());
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
AuthorizationServerConfig
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
{
@Autowired
private TokenStore tokenStore;
@Autowired
private UserAccessService userDetailsService;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception
{
configurer.inMemory()
.withClient(SecurityConstant.CLIENT_ID)
.secret(SecurityConstant.CLIENT_SECRET)
.accessTokenValiditySeconds(SecurityConstant.ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(SecurityConstant.REFRESH_TOKEN_VALIDITY_SECONDS)
.scopes(SecurityConstant.SCOPE_READ, SecurityConstant.SCOPE_WRITE)
.authorizedGrantTypes(SecurityConstant.GRANT_TYPE_PASSWORD, SecurityConstant.REFRESH_TOKEN)
.resourceIds(SecurityConstant.RESOURCE_ID);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
{
endpoints.tokenStore(tokenStore)
.userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenEnhancer(new CustomTokenEnhancer());
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception
{
super.configure(security);
security.checkTokenAccess("permitAll()");
}
}
ResourceServerConfig
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
{
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources)
{
resources.tokenStore(tokenStore)
.resourceId(SecurityConstant.RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception
{
http.formLogin().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers(Uri.DIET + "/**").authenticated()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
И я получаю сообщение об ошибке, подобное этому, когда я пытаюсь войти в сеть
Не удалось загрузить ресурс: сервер ответил со статусом 403 ()
Доступ к XMLHttpRequest по адресу https: //---.---.---: 8443 / folder / oauth / token 'from origin' https: // ---.- --.--- 'был заблокирован политикой CORS: Ответ на предполётный запрос не проходит проверку контроля доступа: у него нет статуса HTTP ok.