英文:
Gorilla sessions not working for CORS from client
问题
我已经设置了一个Go的REST API。在登录时,我执行以下操作:
session, _ := store.New(r, sessionId)
session.Options.MaxAge = 12 * 3600
err := session.Save(r, w)
//处理错误
检查会话时,我有类似以下的代码:
session, err := store.Get(r, sessionId)
//处理错误
if session.IsNew {
    http.Error(w, "未经授权的会话。", http.StatusUnauthorized)
    return
}
如果我使用Postman发送请求,一切正常,但是当我从我的客户端发送请求时,我收到401错误。你们有没有遇到过类似的情况?存储是一个CookieStore。
我已经检查了ID,我用一个静态字符串替换了sessionId变量。Gorilla session使用Gorilla context来注册一个新的请求,当我从Postman发送请求时,context.data[r]不为空,但是从客户端发送请求时,它始终为空,即始终是一个新的会话。
https://github.com/gorilla/context/blob/master/context.go - 第33行
它在以下位置被调用:
https://github.com/gorilla/sessions/blob/master/sessions.go - 第122行
在CookieStore.Get函数中使用:
https://github.com/gorilla/sessions/blob/master/store.go - 第77行
编辑1:
对于客户端,我使用Polymer和XMLHttpRequest进行了尝试。
Polymer:
<iron-ajax
  id="ajaxRequest"
  auto
  url="{{requestUrl}}"
  headers="{{requestHeaders}}"
  handle-as="json"
  on-response="onResponse"
  on-error="onError"
  content-type="application/json"
>
</iron-ajax>
处理函数:
onResponse: function(response){
  console.log(response.detail.response);
  this.items = response.detail.response
},
onError: function(error){
  console.log(error.detail)
},
ready: function(){
  this.requestUrl = "http://localhost:8080/api/fingerprint/company/" + getCookie("companyId");
  this.requestHeaders = {"Set-cookie": getCookie("api_token")}
}
并且cookie成功传递到后端。
XMLHttpRequest:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
    if(xmlhttp.status == 200){
      //做一些操作
    }else if(xmlhttp.status == 401){
      page.redirect("/unauthorized")
    }else{
      page.redirect("/error")
    }
  }
}
xmlhttp.open("GET","http://localhost:8080/api/fingerprint/company/" + getCookie("companyId"),true);
xmlhttp.setRequestHeader("Set-cookie", getCookie("api_token"));
xmlhttp.send();
编辑2:
所以我尝试使用Fiddler进行调试(感谢建议),我发现从Postman发送的请求中有一个粗体条目Cookies / Login,而来自客户端的请求没有。有没有办法获取/设置这个值?在身份验证请求中,我收到了一个包含所有所需数据的set-cookie头,但是我无法在客户端获取它。我收到了Refused to get unsafe header set-cookie的错误。
英文:
I have set up a Go rest api. And on login I do this:
session, _ := store.New(r, sessionId)
session.Options.MaxAge = 12 * 3600
err := session.Save(r, w)
//treat error
and for checking the session i have smth like this:
	session, err := store.Get(r, sessionId)
    //treat error
	if session.IsNew {
		http.Error(w, "Unauthorized session.", http.StatusUnauthorized)
		return
	}
If I do the requests from postman it works fine, but when I do them from my client I get 401. Has any of you experienced something like this? The store is a CookieStore.
I already checked the id's, I replaced sessionId variable with a static string. Gorilla session uses gorilla context to register a new request and when I do the request from postman context.data[r] is not null, but from the client it is always null -> always a new session.
https://github.com/gorilla/context/blob/master/context.go - line 33
it is called in
https://github.com/gorilla/sessions/blob/master/sessions.go - line 122
wich is used in the CookieStore.Get function in
https://github.com/gorilla/sessions/blob/master/store.go - line 77
EDIT 1:
For the client I use polymer and I tried xmlhttp too.
Polymer:
<iron-ajax
  id="ajaxRequest"
  auto
  url="{{requestUrl}}"
  headers="{{requestHeaders}}"
  handle-as="json"
  on-response="onResponse"
  on-error="onError"
  content-type="application/json"
  >
</iron-ajax>
and the handlers
  onResponse: function(response){
    console.log(response.detail.response);
    this.items = response.detail.response
  },
  onError: function(error){
    console.log(error.detail)
  },
  ready: function(){
    this.requestUrl = "http://localhost:8080/api/fingerprint/company/" + getCookie("companyId");
    this.requestHeaders = {"Set-cookie": getCookie("api_token")}
  }
and the cookie successfully reaches the backend.
And xmlhttp:
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
      if(xmlhttp.status == 200){
        //do stuff
      }else if(xmlhttp.status == 401){
        page.redirect("/unauthorized")
      }else{
        page.redirect("/error")
      }
    }
  }
  xmlhttp.open("GET","http://localhost:8080/api/fingerprint/company/" + getCookie("companyId"),true);
  xmlhttp.setRequestHeader("Set-cookie", getCookie("api_token"));
  xmlhttp.send();
EDIT 2:
So I tried debugging with fiddler(thanks for the suggestion) and i found out that the request from postman has an bold entry Cookies / Login and the request from the client does not. Any idea how to get/set that value? It is somehow automatically set in Postman. In the authentication request I get a set-cookie header that has all the data that I need but I can't get it on the client. I get Refused to get unsafe header set-cookie.
答案1
得分: 3
问题在于在客户端中,请求需要设置withCredentials = true,然后浏览器会处理一切。它从set-cookie头部获取cookie,并通过cookie头部发送cookie。所以,最终,这不是一个gorilla sessions的问题。
英文:
The problem is that in the client the requests need to have withCredentials = true and after that the browser deals with everything. It gets the cookie from the set-cookie header and it sends the cookies via the cookie header. So, after all, it was not a gorilla sessions problem.
答案2
得分: 0
如果其他人遇到了和我一样的问题,并且你想要将所有域名/通配符添加到白名单(或者有一个域名列表数组可以进行扫描),你可以像这样做。
domain_raw := r.Host
domain_host_parts := strings.Split(domain_raw, ".")
domain := domain_host_parts[1] + "." + domain_host_parts[2]
domains := getDomains() // 存储允许的域名切片
has_domain := false
for _, d := range domains {
    if d == domain {
        has_domain = true
        break
    }
}
if has_domain == false {
    return
} else {
    w.Header().Add("Access-Control-Allow-Origin", "https://"+domain_raw)
    w.Header().Add("Access-Control-Allow-Credentials", "true")
}
我喜欢Go语言。
英文:
If anyone else is having the same problem I was having and you want to whitelist all domains/wildcards (or have a list of domains in an array you can scan through), you can do something like this.
domain_raw := r.Host
domain_host_parts := strings.Split(domain_raw, ".")
domain := domain_host_parts[1] + "." + domain_host_parts[2]
domains := getDomains() // stores a slice of all your allowable domains
has_domain := false
for _, d := range domains {
	if d == domain {
		has_domain = true
		break
	}
}
if has_domain == false {
	return
} else {
	w.Header().Add("Access-Control-Allow-Origin", "https://"+domain_raw)
	w.Header().Add("Access-Control-Allow-Credentials", "true")
}
I love go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论