java - 使用 Jersey 通过 REST 获取 CSRF token 并在登录中使用它

标签 java spring rest spring-security jersey-2.0

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

首先,我向 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 header 并从那里获取 CSRF token 。然后我以这种方式发出帖子请求:

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

使用此请求 header :

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

使用 Chrome 的插件 postman ,我可以发出正确的登录帖子请求,但是对于 Jersey,我无法正确发送 CSRF token (我收到 403 响应)。

这是响应:

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

这是 Jersey 代码:

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));

感谢您的宝贵时间。

最佳答案

经过反复试验,我找到了解决方案。对于 REST 配置与 spring security 通信来说,重要的是要考虑 count cookies(如 Roman Vottner 所指出的)。必须存在的重要 cookie 是 JSESSIONID 和 header X-CSRF-TOKEN(或服务器中配置的任何 header 名称),因此在初始请求中捕获它们并再次发送它们。

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

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));

关于java - 使用 Jersey 通过 REST 获取 CSRF token 并在登录中使用它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31548248/

相关文章:

reactjs - 我在哪里可以练习 DELETE、PUT 和 POST 请求。是否存在一些允许执行此操作的免费 API?

java - 从 google play developer rest api 访问编辑方法

java - 带有附加 url 参数的 Restful 帖子?

java - 查询今天、一周内、一个月内

java - 公共(public)语言基础设施如何工作以及其目的是什么?

java - Spring Scheduled 注解是如何工作的

java - 如何在两个框架之间分割一个框架?

java - 这是三层架构吗?

java - 无法配置数据源 : 'url' attribute is not specified and no embedded datasource could be configured. SPRING

api - Flowdock REST API - 简单集成