I am developing a client-server architecture for the first time and I have some problems to configure the server to accept CORS.
I've read, searched and test a lot, but I can not make it work in my system, I do not know what is wrong.
I developed the client inAngular and the web service in Spring Boot 2.0.4 with Oauth2 security. On the server there are running an Apache that only accepts requests from port 443 to serve the web and redirect requests through port 8443 to the web service deployed in Tomcat 8.5 that is listening on port 8081.
<VirtualHost _default_:8443>
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/
DocumentRoot /var/www/html
...
Changes that I made in the Apache configuration
<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());
}
}
And i getting an error message like this when i try to login in the web
Failed to load resource: the server responded with a status of 403 ()
Access to XMLHttpRequest at ' https://---.---.---:8443/folder/oauth/token ' from origin 'https:// ---.---.---' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Are you sending the header "with credentials" on the client side? If it`s an angular 7 app you have to allow the with credentials header on the server side, adding on the cors configuration, and add an interceptor on the client side for every http client request. Besides that, you should not let "*" as allowed origins or the with credentials header will not work.
On Angular create this:
@Injectable()
export class CredentialsInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
request = request = request.clone({
withCredentials: true
});
return next.handle(request);
}
}
And add to app.module:
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: CredentialsInterceptor,
multi: true
}
Another problem could be the order of the cors filter, it should be before the security filter on filterChain. You can handle it, with something like this:
@Bean
FilterRegistrationBean<CorsFilter> corsFilter(CorsConfigurationSource
corsConfigurationSource)
{
CorsFilter corsFilter = new CorsFilter(corsConfigurationSource);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>
();
bean.setFilter(corsFilter);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.