使用ReactJS应用程序命中端点时,KeyClope安全的Spring引导应用程序CORS错误
我有一个ReactJS和JavaSpring引导应用程序,它们都由KeyClope 11.0.2保护 KeyClope在端口8083上,ReactJS在3000上,Spring应用程序在8085上。 如果我尝试使用下面提供的配置,我将无法访问我的端点,并且会出现CORS错误 火狐:使用ReactJS应用程序命中端点时,KeyClope安全的Spring引导应用程序CORS错误,reactjs,spring-boot,keycloak,Reactjs,Spring Boot,Keycloak,我有一个ReactJS和JavaSpring引导应用程序,它们都由KeyClope 11.0.2保护 KeyClope在端口8083上,ReactJS在3000上,Spring应用程序在8085上。 如果我尝试使用下面提供的配置,我将无法访问我的端点,并且会出现CORS错误 火狐: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localho
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f52216b1-c235-4328-a2f9-d8448c3bf886&login=true&scope=openid. (Reason: CORS request did not succeed).
Chrome和Microsoft Edge:
Access to XMLHttpRequest at 'http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f57ffa9f-9679-4476-aa03-af86c3abb3c2&login=true&scope=openid' (redirected from 'http://localhost:8085/api/worker/create/product') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
xhr.js:184 GET http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f57ffa9f-9679-4476-aa03-af86c3abb3c2&login=true&scope=openid net::ERR_FAILED
当我试图用邮递员到达终点时,我能够到达终点。下面是我的KeyClope Web安全配置。该配置使用application.properties文件来配置KeyClope适配器。
当我在配置中设置.authorizeRequests().antMatchers(“/**”).permitAll()
时,我还能够从浏览器和邮递员中点击我的端点
@KeycloakConfiguration
public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authBuilder) throws Exception {
final KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider();
authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
authBuilder.authenticationProvider(authProvider);
}
/**
* Call superclass configure method and set the Keycloak configuration
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.csrf().disable()
.cors()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().anonymous()
//.and().authorizeRequests().antMatchers("/**").permitAll() //Uncomment for requests to be allowed!
.and().authorizeRequests().antMatchers("/api/admin/**").hasRole("ADMIN")
.and().authorizeRequests().antMatchers("/api/manager/**").hasAnyRole("MANAGER")
.and().authorizeRequests().antMatchers("/api/worker/**").hasRole("WORKER")
.anyRequest().authenticated();
}
/**
* Setup Auth Strategy. Don't add prefixes and suffixes to role strings
*/
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
/**
* Don't use keycloak.json. Instead, use application.yml properties.
* @return
*/
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
下面是application.properties的一部分,用于设置KeyClope:
spring:
jersey:
type: filter
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/token
jwk-set-uri: http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/certs
keycloak:
realm: sorcerer_realm
auth-server-url: http://localhost:8083/auth/
ssl-required: external
resource: event_sorcerer
verify-token-audience: true
credentials:
secret-jwt:
secret: d84611c9-af79-423b-b12c-bfa7fec23e85
use-resource-role-mappings: true
confidential-port: 0
下面是我的ReactJS应用程序的KeyClope适配器设置:
const keycloakConfig = {
"clientId": "event_sorcerer_frontend",
"realm": "sorcerer_realm",
"auth-server-url": "http://localhost:8083/auth/",
"url": "http://localhost:8083/auth",
"ssl-required": "external",
"resource": "event_sorcerer",
"public-client": true,
"verify-token-audience": true,
"use-resource-role-mappings": true,
"confidential-port": 0
};
const keycloak = new Keycloak(keycloakConfig);
const initKeycloak = (onSuccessCallback, onFailureCallback) => {
let success = false;
timeoutWrapper(() => {
if(!success){
onFailureCallback();
}
});
keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',
pkceMethod: 'S256',
}).then((isAuthenticated) => {
success = true;
if(isAuthenticated) {
onSuccessCallback();
} else {
login();
}
});
}
以下是我将请求发送到服务器的方式:
export const Request = {
configureAxiosDefault: () => {
axios.defaults.baseURL = axiosDefaultConfiguration.baseUrl;
},
create: (data, endpoint, callback, errorCallback, finalCallback) => {
axios.post(serverEndpoint + endpoint, {
data: data,
headers: {
Authorization: `Bearer ${UserService.getToken()}`
}
})
.then(response => Utility.isEmpty(callback) ? defaultCallback(response) : callback(response))
.catch(response => Utility.isEmpty(errorCallback) ? defaultErrorCallback(response) : errorCallback(response))
.finally(response => {
if(!Utility.isEmpty(finalCallback)) {
finalCallback(response);
}
});
},
}
这是我的前端密钥斗篷配置。后端相同,只是访问类型是机密的,根/基url不同(不是3000而是8085):
以下是我的CORS配置bean:
@Configuration
public class CORSConfiguration {
/**
* Setup CORS
* @return
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
config.setAllowedMethods(Arrays.asList(CorsConfiguration.ALL));
config.setAllowedHeaders(Arrays.asList(CorsConfiguration.ALL));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return source;
}
}
最后,这是我的终点。URL解析为api/worker/create/product
@RestController
@RequestMapping(ControllerEndpointsPrefix.WORKER + "/create")
public class CreationController {
@Autowired
private UserAgregate userAgregate;
@PostMapping("/product")
public boolean createProduct(@RequestBody CreateProductCommand command) {
return true;
}
}
我已经设法解决了这个问题。 问题不在服务器端,而是在客户端
configureAxiosDefault: () => {
axios.defaults.baseURL = axiosDefaultConfiguration.baseUrl;
axios.defaults.headers.Authorization = `Bearer ${UserService.getToken()}`
},
create: (data, endpoint, callback, errorCallback, finalCallback) => {
axios.post(serverEndpoint + endpoint, data)
.then(response => Utility.isEmpty(callback) ? defaultCallback(response) : callback(response))
.catch(response => Utility.isEmpty(errorCallback) ? defaultErrorCallback(response) : errorCallback(response))
.finally(response => {
if(!Utility.isEmpty(finalCallback)) {
finalCallback(response);
}
});
},
服务器无法处理令牌,因为我将其作为JSON对象属性发送。这些变化使一切正常
所以,CORS根本不是问题。问题是请求不包含授权标头
关于keydepeat有很多StackOverflow问题,其中一些是不完整和神秘的。由于OpenJDK、JDK版本等原因,我遇到了大量错误。
如果有人需要解释和解决方案,我的存储库中提供了Spring启动配置:
https://github.com/milosrs/EventSorcererBackend