【问题标题】:Spring Security authentication cross-origin with cookies vs Authorization headerSpring Security 跨域身份验证与 cookie 与授权标头
【发布时间】:2018-01-26 04:04:24
【问题描述】:

我正在使用 Spring Security 对我的 REST API 进行身份验证。身份验证工作正常,Spring Security 返回一个带有Set-Cookie 的令牌。 rememberMe 功能开启,同样在 cookie 中返回。

当我发出后续请求时,除非我在 Authorization 标头中发送用户名/密码,否则身份验证会失败,而当我在邮递员中进行测试时,它可以工作。我看到它在请求的cookie中添加了JSESSIONID

由于 cookie 为 Http-Only cookie,我认为我无法在我的 JavaScript 函数中读取它们。

那么我该如何认证用户呢?我假设如果服务器返回一个带有set-cookie 的cookie,浏览器应该为每个请求自动附加它。

登录客户端请求:

context.$http.get(url, {
    headers:
    {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
      'Authorization': auth
    }
  }

请求标头:

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4
Access-Control-Request-Headers:access-control-allow-methods,access-control-allow-origin,authorization
Access-Control-Request-Method:GET
Connection:keep-alive
DNT:1
Host:localhost:9000
Origin:http://localhost:8080
Referer:http://localhost:8080/login?redirect=%2F
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36

响应标头:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:8080
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:13
Content-Type:application/json;charset=UTF-8
Date:Fri, 18 Aug 2017 05:40:55 GMT
Expires:0
Pragma:no-cache
Set-Cookie:remember-me=dTVTMi94dnVkQzJtYXRFYmJkR1VKZz09OjA1T1F4RXVOV0RiTEx4VFdUSVByeGc9PQ; Max-Age=86400; Expires=Sat, 19-Aug-2017 05:40:55 GMT; Path=/; Secure; HttpOnly
Set-Cookie:JSESSIONID=4A856E0216191E8601100B600E4A227B; Path=/; HttpOnly
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

后续请求获取数据:

this.$http.get(url).then(function (res) {
          this.items = res.data
        })

客户请求:

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4
Connection:keep-alive
DNT:1
Host:localhost:9000
Origin:http://localhost:8080
Referer:http://localhost:8080/Languages
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36

服务器响应:

HTTP/1.1 401
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Allow-Origin: http://localhost:8080
Vary: Origin
Access-Control-Allow-Credentials: true
WWW-Authenticate: Basic realm="Realm"
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 18 Aug 2017 05:43:26 GMT

{timestamp: 1503038407254, status: 401, error: "Unauthorized",…}
error :
"Unauthorized"
message:"Full authentication is required to access this resource"
path:"/languages"
status:401
timestamp:1503038407254

添加withCredentials : true:

GET /languages HTTP/1.1
Host: 192.168.16.142:12345
Connection: keep-alive
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
Access-Control-Allow-Methods: GET,PUT,POST,DELETE
DNT: 1
Referer: http://localhost:8080/languages
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4

回复:

Access-Control-Allow-Origin:*
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json;charset=UTF-8
Date:Mon, 21 Aug 2017 06:26:24 GMT
Expires:0
Pragma:no-cache
Transfer-Encoding:chunked
Vary:Origin
WWW-Authenticate:Basic realm="Realm"
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

仅供参考:我在前端使用 vuejs。

【问题讨论】:

  • 你试过了吗:Vue.http.options.xhr = {withCredentials: true}
  • 是的,我试过了
  • 你能添加完整的 http 请求和响应吗?即包含相应请求和响应的 URL。
  • 您知道浏览器执行的第一个请求是 CORS preflight OPTIONS 请求,对吧? developer.mozilla.org/en-US/docs/Web/HTTP/… 为了让浏览器认为成功,服务器必须返回一个 Access-Control-Allow-Headers 响应标头,该标头的值中包含“授权”。但是问题中的响应标头不包含它,因此要么您显示了错误的响应标头,要么预检实际上失败了。该问题也没有显示该响应的响应代码。你确定不是401吗?
  • 您的浏览器在 devtools 控制台中记录的究竟是什么消息?另外,请注意您应该从客户端请求代码中删除 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'。这些标头是服务器要发送的 response 标头。向他们发送请求标头的唯一影响是触发将失败的 CORS 预检。在这种情况下,您要发送的唯一请求标头是 Authorization

标签: cookies spring-boot spring-security vuejs2


【解决方案1】:

仔细查看您的响应/请求流程后,您将请求从端口 8080 发送到端口 9000,这些请求会触发同源策略 (CORS) 规则。默认情况下,CORS 请求不会发送下面链接中记录的凭据/cookie。要启用凭据/cookie 传播,您需要在 AJAX 调用中设置“withCredentials”标志。

此外,您似乎正在使用 vuejs。要启用 withcredentials,您需要使用以下设置。

Vue.http.options.credentials = true;

MDN - Request with credentials

【讨论】:

  • 我添加了Vue.http.options.xhr = {withCredentials: true}我仍然收到来自服务器的401
  • @Sam 可以在使用 withCredentials 时添加请求有效负载吗?
  • @Sam 你用的是spring-boot,如果用,是哪个版本的?
  • XMLHttpRequest 无法加载 ''。对预检请求的响应未通过访问控制检查:响应中“Access-Control-Allow-Credentials”标头的值为“”,当请求的凭据模式为“包含”时,该值必须为“真”。因此,Origin 'localhost:8080' 不允许访问。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
  • Spring boot 版本为:1.5.6
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 2015-09-13
  • 2011-09-27
  • 2014-05-11
  • 2010-11-22
  • 2011-07-17
相关资源
最近更新 更多