我是按照Spring Blog(https://spring.io/guides/tutorials/spring-security-and-angular-js/)的教程来的。但是我从一个现有的Spring应用程序开始,因此我不使用Spring Boot开始,我必须找到一种方法来实现XML和Java配置混合风格的组件。
这是我的CORS过滤器:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
public SimpleCORSFilter(){
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
//x-auth-token is a custom header for Spring Security AngularJS implementation
response.setHeader("Access-Control-Allow-Headers", "Options, authentication, authorization, X-Auth-Token, Origin, X-Requested-With, Content-Type, Accept, XSRF-TOKEN");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
System.out.println("OPTIONS request from AngularJS");
response.setStatus(HttpServletResponse.SC_OK);
}
chain.doFilter(req, response);
}
@Override
public void destroy() {}
这是我的CsrfHeaderFilter.java,基本上是从教程中复制过来的:
@Component
public class CsrfHeaderFilter extends OncePerRequestFilter{
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println("CsrfHeaderFilter vvv");
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if(csrf != null){
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
System.out.println("CSRFToken Value: "+token);
if(cookie == null || token != null && !token.equals(cookie.getValue()) ){
cookie = new Cookie("XSRF-TOKEN", token); //use XSRF-TOKEN as the response header for CSRF token
cookie.setPath("/");
response.addCookie(cookie);
}
}
System.out.println("CsrfHeaderFilter ^^^");
filterChain.doFilter(request, response);
}
并且Csrfhead erFilter配置为在Spring的CsrfFilter之后:
<sec:custom-filter ref="csrfHeaderFilter" after="CSRF_FILTER" />
<sec:csrf token-repository-ref="csrfTokenRepository"/>
csrfTokenRepostory:
@Configuration
public class CustomCsrfTokenRepository {
@Bean
public CsrfTokenRepository csrfTokenRepository(){
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
repository.setParameterName("_csrf");
return repository;
}
}
我有自己的身份验证过滤器,带有自定义登录URL:
public class CustomerAuthenticationTokenProcessingFilter extends AbstractAuthenticationProcessingFilter{
private static final String SECURITY_TOKEN_HEADER = "x-auth-token";
private static final String AUTHORIZATION_HEADER = "authorization";
@Autowired
private CustomerTokenAuthenticationService tokenAuthenticationService;
@Autowired
CustomerAuthenticationService customerAuthenticationService;
@Autowired
@Qualifier("customerAuthenticationManager")
AuthenticationManager authenticationManager;
protected CustomerAuthenticationTokenProcessingFilter(){
super("/company/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
Authentication authentication = null;
//Authentication Logics...
...
return authentication;
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
}
}
当然,还有一个自定义注销网址:
<sec:logout invalidate-session="true" delete-cookies="JSESSION,XSRF-TOKEN"
logout-url="/resource/logout" success-handler-ref="customerLogoutSuccessHandler"/>
customerLogoutSuccessHandler:
public class CustomerLogoutSuccessHandler implements LogoutSuccessHandler{
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
if (authentication != null && authentication.getDetails() != null) {
try {
SecurityContextHolder.clearContext();
System.out.println("User Successfully Logout");
response.setStatus(HttpServletResponse.SC_OK);
} catch (Exception e) {
e.printStackTrace();
e = null;
}
}
}
}
AngularJS代码非常简单。最初我显示了登录表单,只是向Spring的/company/loginendpoint发出HTTP POST请求,但不知为什么我的AngularJS应用程序没有获得所需的CSRF令牌……所以我在启动时添加了一个HTTP GET请求,以从打开的URL(access=“permitAll()”)请求,以便为我即将到来的请求获取XSRF-token。登录和注销工作正常,直到我再次登录。错误为“POST”http://localhost:8080/company/login403(禁止)”和“在请求参数'_CSRF'或标头'X-XSRF-Token'上发现无效的CSRF令牌”
我认为我的浏览器中的cookie有问题。当我在CORS过滤器中输出cookie数据时,我可以看到传递给Spring之前的相同XSRF-TOKEN,并且Spring的CsrfFilter拒绝了进一步的请求,因为CSRF令牌不正确。
FilterChainProxy DEBUG - /company/login at position 3 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
CsrfFilter DEBUG - Invalid CSRF token found for http://localhost:8080/company/login
也许我在注销部分遗漏了一些功能?如果我的请求从未通过Spring的CsrfFilter,我该如何更新XSRF-TOKEN?
如有必要,请随时向我询问更多详细信息。我真的很想解决这个问题,因为我已经花了很多时间试图找出问题所在:(
所以,在我发布这个答案后不久,我发现了问题。。。
后端服务器配置很好,问题实际上来自AngularJS HTTP请求。由于我遵循Spring博客的教程,我也使用了教程中的AngularJS代码,因为我对AngularJS相当陌生。我创建了更多的函数和控制器来满足我的需要,我使用了$http.get和。成功()和.错误(),这是一个异步调用。不知何故,这导致了Csrf令牌问题。所有这些异步超文本传输协议请求让我非常困惑。所以我决定找到一种方法,等到Http请求完成后再下一个Http请求,看看会发生什么。我有一个工厂来处理登录和注销。
这可能不是最好的方法,但这里是AngularJS代码的一部分:
//Move the initial GET request to a variable
var init = function(){
return $http(
{
url : '/my/url/',
method : 'GET',
}
).then(function(result){
//bunch of debugging messages
return result.data;
})
}
以下是调用我的初始GET请求以获取CSRF令牌的方法,然后在GET请求完成后发出登录POST请求:
var initPromise = init();
initPromise.then(function(result){
$http(
{
url : '/url/to/login',
method : 'POST',
headers : headers
}
).success(function(data, config, headers) {
//debugging messages of course
//getting my data
...
if(data_validation_is_true){
$http({
url : '/my/secured/resource/url',
method : 'GET',
headers :
{
'X-Auth-Token' : token_I_Received
}
}).success(function(data, config, headers){
console.log('/inventory/resource/user request with token, response headers: '+JSON.stringify(headers()));
if (authenticated) {
//authentication successful logic
...
} else {
//authentication unsuccessful logic
...
}
}).error(function(data){
//error handling
...
});
}
}).error(function(data, status) {
//error handling
...
});
})
如果有什么不对的地方,请给我任何建议。
以下是场景: 我使用的是Spring Security 4.0.1,它默认启用了CSRF,直到昨天一切都正常。 昨天,我添加了Spring Security标签,登录(和其他表单工作正常),但一个特殊表单停止工作。 此表单是多部分的,因为上载了两个文件,此表单具有CSRF参数,但服务器正在返回: HTTP状态403-未找到预期的CSRF令牌。您的会话是否已过期? 基本上是这样的: 当然,这是一个完
我使用的是spring security 4.0.1。我一登录,它就会显示我的仪表板。当我点击某个东西时,它会显示以下错误页面: HTTP状态403-未找到预期的CSRF令牌。你的课程过期了吗? 我对它做了一些研究,它说我需要添加这个http。csrf()。禁用()。我无法添加它,因为它告诉我方法和类型httpsecurity是未定义的。 请在下面找到配置代码: 登录。xhtml MyConfig
我是新的Python开发和尝试使用pipenv。我运行命令,它成功运行: 然而,当我在一个新的根项目目录中运行命令时,我收到以下消息:。我怀疑我可能需要修改我的. bashrc,但是我不清楚要向文件中添加什么,或者是否需要修改。
我在Heroku上使用Postgresql数据库托管了一个RoR应用程序,并且一直在使用PG备份工具将数据库从我的应用程序备份到本地机器上。由于该应用程序仍在开发中,它从编程的角度帮助我降低了我的同事对数据库所做的更改。几个月来,我一直在成功地使用PG备份进行捕获和恢复,但最近,当我运行此处所示的典型命令时: 在curl命令执行后,我遇到此错误: 你知道为什么会这样吗?显然,问题是我无法恢复下载的
我使用的是节点0.10。35和grunt指挥部运作良好。现在升级到0.12之后。3 grunt命令已停止工作。 OS:Mac OSX 10.10.1节点:0.12.3 npm:2.9.1 grunt:0.4.5 我认为可能有问题的节点安装所以我清理安装了3-4次 我试着用- node-v0.12.3.pkg 节点版本管理器(nvm) 许多此类问题的解决方案建议使用 然后使用安装本地节点模块。 我遵
我试着做一个文件: 但是得到了错误: Android:命令未找到 我试图设置Android SDK的路径,但没有帮助: 有没有可能解决这个问题? UPD:我正在使用这个软件中的Git Shell:http://git-scm.com/download/win