我能够使用来自https://github.com/dsyer/spring-security-angular/blob/master/vanilla/README.md的示例 Spring Boot Groovy Maven 实现成功运行此配置。当应用程序代码在 Java 和 Gradle 2.3 中实现时,它不起作用。在这种情况下,OPTIONS 响应有一个新的 X-Auth-Token。
尝试将提供的 maven 构建与我的 java 类一起使用,但仍然得到相同的 OPTIONS 401 未经授权的响应。所以这不是 Gradle 问题。
将两个 ResourceApplication Groovy 类复制到我的 Gradle 构建中,Angular ui 成功获得 OPTIONS 200 OK。所以java中的Spring CORS过滤器存在问题。
我有用于 java 和 groovy 的 Gradle 插件,sourceCompatibility 和 targetCompatibility = 1.7
java 版本 "1.8.0_31" Java(TM) SE Runtime Environment (build 1.8.0_31-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, 混合模式)
开发人员控制台日志验证是否从 ui 服务器发送了相同的令牌并由 angular 客户端接收,但报告了 CORS 错误。
Cross-Origin Request Blocked :同源策略不允许在http://localhost:9000/读取远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。本地主机:9000
@SpringBootApplication
@RestController
@EnableRedisHttpSession
public class AngularDemoApplication {
@RequestMapping("/user")
public Principal user(Principal user) {
return user;
}
@RequestMapping("/token")
@ResponseBody
public Map<String,String> token(HttpSession session) {
logger.debug("********** TOKEN *********** = "+session.getId());
return Collections.singletonMap("token", session.getId());
}
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().logout().and().authorizeRequests()
.antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll()
.anyRequest().authenticated().and().csrf().csrfTokenRepository(csrfTokenRepository())
.and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
public static void main(String[] args) {
SpringApplication.run(AngularDemoApplication.class, args);
}
}
@SpringBootApplication
@RestController
@EnableRedisHttpSession
public class ResourceApplication {
@RequestMapping("/")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
@Bean
public HeaderHttpSessionStrategy sessionStrategy() {
return new HeaderHttpSessionStrategy();
}
public static void main(String[] args) {
SpringApplication.run(ResourceApplication.class, args);
}
}
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {
@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", "*");
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-auth-token, x-requested-with");
if (request.getMethod() != "OPTIONS" ) {
chain.doFilter(req, res);
} else {
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
Groovy 版本:
请求方法:OPTIONS
状态码:200 OK
请求标头:
主机:localhost:9000
用户代理:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0
接受:text/html,application/xhtml+xml,application/xml;q= 0.9, / ;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: localhost:8080
Access-Control-Request-Method: GET
Access-Control-Request-Headers: x -auth-token,x-requested-with
连接:保持活动
响应标头:
Access-Control-Allow-Headers:x-auth-token、x-requested-with
Access-Control-Allow-Methods:POST、PUT、GET、OPTIONS、DELETE
Access-Control-Allow-Origin:*
Access- Control-Max-Age: 3600
Content-Length: 0
Date: Tue, 31 Mar 2015 21:20:28 GMT
服务器: Apache-Coyote/1.1
请求方法:GET
状态码:200 OK
请求标头:
主机:localhost:9000 用户代理:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0
Accept: application/json, text/plain, /
Accept-Language: en-US ,en;q=0.5
Accept-Encoding: gzip, deflate
X-Auth-Token: 80e0c2d2-dab4-435d-886e-ae28bc8e636f
X-Requested-With: XMLHttpRequest
响应标头:
Access-Control-Allow-Headers:x-auth-token、x-requested-with
Access-Control-Allow-Methods:POST、PUT、GET、OPTIONS、DELETE
Access-Control-Allow-Origin:*
Access- Control-Max-Age: 3600
内容类型: application/json;charset=UTF-8
日期: Tue, 31 Mar 2015 21:20:28 GMT
服务器: Apache-Coyote/1.1
Strict-Transport-Security: max-age= 31536000; includeSubDomains
Transfer-Encoding: chunked
Referer: localhost:8080/
Origin: localhost:8080
Connection: keep-alive
Redis 服务器密钥:
1)“spring:session:expirations:1427838660000”
2)“spring:session:sessions:80e0c2d2-dab4-435d-886e-ae28bc8e636f”
Java版本:
请求方法:OPTIONS
状态码:401 Unauthorized
请求标头:
主机:localhost:9000
用户代理:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0
接受:text/html,application/xhtml+xml,application/xml;q= 0.9, / ;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: localhost:8080
Access-Control-Request-Method: GET
Access-Control-Request-Headers: x -auth-token,x-requested-with
连接:保持活动
响应标头:
Access-Control-Allow-Headers:x-auth-token、x-requested-with
Access-Control-Allow-Methods:POST、PUT、GET、OPTIONS、DELETE
Access-Control-Allow-Origin:*
Access- Control-Max-Age:3600
允许:GET、HEAD、POST、PUT、DELETE、TRACE、OPTIONS、PATCH
内容长度:0
日期:2015 年 3 月 31 日星期二 20:50:26 GMT
服务器:Apache-Coyote/1.1
Strict -传输安全:max-age=31536000;includeSubDomains
WWW-Authenticate: Basic realm="Spring"
X-Auth-Token: 8af7e1f4-e723-4ce6-8d21-54a7b10369f8
Redis 服务器密钥:
1)“spring:session:sessions:8af7e1f4-e723-4ce6-8d21-54a7b10369f8”
2)“spring:session:expirations:1427836860000”
3)“spring:session:sessions:c6a6cc31-eddc-40dd-99de -a6e1eecbf519"