2015-07-21 71 views
1

使用Jersey 2.19,如何从使用Spring Security 3的服务器获取CSRF令牌并成功登录?我有两个项目,一个使用REST的客户端和一个使用JHipster创建的服务器。使用Jersey通过REST获取CSRF令牌并在登录中使用它

首先,我正在做一个GET请求到http://localhost:8080和我得到这个响应头:

Cache-Control:no-cache, no-store, max-age=0, must-revalidate 
Content-Language:en 
Content-Length:17229 
Content-Type:text/html;charset=utf-8 
Date:Tue, 21 Jul 2015 19:24:40 GMT 
Expires:0 
Last-Modified:Thu, 02 Jul 2015 17:07:31 GMT 
Pragma:no-cache 
Server:Apache-Coyote/1.1 
Set-Cookie:CSRF-TOKEN=0902449b-bac7-43e8-bf24-9ec2c1faa48b; Path=/ 
X-Application-Context:application:dev:8081 
X-Content-Type-Options:nosniff 
X-XSS-Protection:1; mode=block 

我提取的Set-Cookie头,我从那里得到的CSRF令牌。然后我做一个POST请求是这样的:

http://localhost:8080/api/authentication?j_username=user&j_password=user&submit=Login 

有了这个请求头:

Content-Type: application/x-www-form-urlencoded 
X-CSRF-TOKEN: <extracted token> 

使用Chrome的插件邮递员,我可以为登录正确的post请求,但新泽西州,我无法正确发送CSRF令牌(我得到403响应)。

这是响应:

{"timestamp":1437507680089,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/api/authentication"} 

这是球衣代码:

WebTarget hostTarget = getClient().target("http://localhost:8080"); 

Response r = hostTarget.request().get(); 
String header = r.getHeaderString("Set-Cookie"); 
String csrf = null; 

List<HttpCookie> cookies = HttpCookie.parse(header); 

for (HttpCookie c : cookies) { 
    if("CSRF-TOKEN".equals(c.getName())){ 
     csrf = c.getValue(); 
     break; 
    } 
} 

WebTarget loginTarget = hostTarget.path("/api/authentication"); 
loginTarget = loginTarget.queryParam("j_username", username) 
    .queryParam("j_password", password) 
    .queryParam("submit", "Login"); 

Builder req = loginTarget.request(MediaType.APPLICATION_JSON_TYPE); 
if (csrf != null) { 
    req = req.header("X-CSRF-TOKEN", csrf); 
} 

Response cr = req.post(Entity.entity(null, 
     MediaType.APPLICATION_FORM_URLENCODED_TYPE)); 

System.out.println("Response: " + cr.readEntity(String.class)); 

感谢您的时间。

+1

您是否在通过邮递员发送CSRF cookie令牌不可用时进行检查?也许调用成功,因为cookie可用于令牌 –

+0

使用邮递员,如果我省略了X-CSRF-TOKEN我在请求参数'_csrf'或头部'X-CSRF'上找到“403无效的CSRF令牌null' -TOKEN”。”使用_csrf作为请求参数或所提到的标题与邮递员一起工作。不过,当我在客户端代码中省略CSRF令牌用法时,我仍然得到问题中提到的403响应。 – dovahkiin

回答

1

经过多次试验和错误,我找到了解决方案。重要的是要采取计数cookies(如罗曼沃特纳所示)REST配置与春季安全进行通信。必须存在的重要cookie是JSESSIONID和标题X-CSRF-TOKEN(或者服务器中配置的任何标题名称),因此将它们捕获到初始请求中并再次发送。

我决定以这种方式将所有的cookie发送到服务器。

WebTarget hostTarget = getClient().target("http://localhost:8080"); 

Response r = hostTarget.request().get(); 
String headerCookies = r.getHeaderString("Set-Cookie"); 

Map<String, NewCookie> cookies = r.getCookies(); 
String csrf = cookies.get("CSRF-TOKEN").getValue(); 

WebTarget loginTarget = hostTarget.path("/api/authentication"); 
loginTarget = loginTarget.queryParam("j_username", username) 
    .queryParam("j_password", password) 
    .queryParam("submit", "Login"); 

Builder req = loginTarget.request(MediaType.APPLICATION_JSON_TYPE); 
req = req.header("Cookie", headerCookies); 

if (csrf != null) { 
    req = req.header("X-CSRF-TOKEN", csrf); 
} 

Response cr = req.post(Entity.entity(null, 
     MediaType.APPLICATION_FORM_URLENCODED_TYPE)); 

//The response is empty (in my case) with status code 200 
System.out.println("Response: " + cr.readEntity(String.class)); 
相关问题