我有一个RESTfull后端实现了在localhost上运行的Spring安全性:8080,一个Login过滤器响应登录请求并在头文件中放置了一个令牌,我甚至没有实现一个Endpoint方法,这一切都是由Spring Security魔术由以下代码行组成:
protected void configure(HttpSecurity http) throws Exception {
// disable caching
http.headers().cacheControl();
http.csrf().disable() // disable csrf for our requests.
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
…
前端是Angularjs Nodejs NPM Bower项目,在localhost:8000上运行静态http服务器。在前端,我按如下方式发出一个简单的POST请求:
$scope.login = function () {
var data = {
"username":$scope.username,
"password":$scope.password
}
$http({
url: baseUrl,
method: "POST",
data: data
}).then(function (response) {
console.log("###### SUCCESS #####");
var headers = response.headers();
console.log("headers: "+JSON.stringify(headers));
var token = headers.authorization.split(" ")[1];
console.log("token: "+token);
$http.defaults.headers.common['Authorization'] = token;
$location.path("/view1");
}, function (responseData) {
// called asynchronously if an error occurs
// or server returns responseData with an error status.
console.log("###### FAIL #####");
console.log("Response: "+JSON.stringify(responseData));
$window.alert("Failed to Login");
});
这就像IE中的魅力(也有curl,wget和python请求),但它在Chrome和Safary上惨遭失败。 我知道那些浏览器正在阻止CORS POST,一旦到达后端就使请求为空,事实上当我从后端注销请求时我看不到任何数据。我尝试了所有可能的组合:
前端方面:
1)$ http(方法:POST)
2)$ http.post(
3)添加标志:Access-Control-Allow-Origin,Access-Control-Expose等
4)添加所有可能的标题组合:'Content-Type':'application /
浏览器端:
1)使用标志启动chrome: - disable-web-security
2)安装Chrome扩展程序CORS
后端方:
1)Spring Security禁用csfr
2)Spring Security Permit all
3)Spring Security HttpMethod.OPTION
没什么,NHOTING为我工作了!
有什么我想念的吗?
是否有其他方式发送POST请求?
修改
如上所述,我修改了以下类:
WebSecurityConfig:
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new CORSFilter(), BasicAuthenticationFilter.class)
并将CORSFilter实现为建议。
我还按建议添加了WebConfig类:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8000")
.allowedMethods("PUT", "POST");
}
}
由于登录过滤器抛出空字符串:
com.fasterxml.jackson.databind.JsonMappingException:由于输入结束而没有要映射的内容
春天的安全部门会对此进行聊天,拒绝访问。
我还试图将前端服务器移到8000(4200,7000等)的其他端口上但没有成功。
答案 0 :(得分:1)
您需要在春季启用Cors支持。在WebConfig中,您可以覆盖addCorsMappings
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:4200"); //url of where angular is running.
}
}
这使得整个应用程序的角色成为可能。您还可以更具体地使用允许特定标头和方法的映射。
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3");
}
您还可以在类和方法级别允许用户@CrossOrgin
@CrossOrigin(origin = "http://domain2.com",
maxAge = 3600)
public class ApiController {
}
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html
答案 1 :(得分:0)
之前我使用过CORS过滤器,效果很好:
public class CORSFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1");
}
filterChain.doFilter(request, response);
}
}
然后将其添加到您的配置中:
.addFilterBefore(new CORSFilter()), BasicAuthenticationFilter.class)