我在聊天应用程序中使用基于Cookie的令牌身份验证时遇到问题.我正在使用带有标准Net库的GO后端来向响应Cookie添加令牌.当用户通过密码验证时(通过发布到身份验证服务器上的/LOGIN路径),响应Cookie应该包含用于生成API令牌的访问令牌和用于重新生成访问令牌的刷新令牌.
下面是一个标记文件,其中包含我的开发环境中的应用程序服务的 struct .每台服务器都使用本地主机上的Go Net/http在顺序端口上运行(未显示无关的服务).
auth_server (
dependencies []
url (scheme "http" domain "localhost" port "8081")
listenAddress ":8081"
endpoints (
/jwtkeypub (
methods [GET]
)
/register (
methods [POST]
)
/logout (
methods [POST]
)
/login (
methods [POST]
)
/apitokens (
methods [GET]
)
/accesstokens (
methods [GET]
)
)
jwtInfo (
issuerName "auth_server"
audienceName "auth_server"
)
)
message_server (
dependencies [auth_server]
url (scheme "http" domain "localhost" port "8083")
listenAddress ":8083"
endpoints (
/ws (
methods [GET]
)
)
jwtInfo (
audienceName "message_server"
)
)
static (
dependencies [auth_server, message_server]
url (scheme "http" domain "localhost" port "8080")
listenAddress ":8080"
)
这是在登录时设置Cookie的代码.这发生在密码判断之后
// Set a new refresh token
refreshToken := s.jwtIssuer.StringifyJwt(
s.jwtIssuer.MintToken(userId, s.jwtIssuer.Name, RefreshTokenTTL),
)
kit.SetHttpOnlyCookie(w, "refreshToken", refreshToken, int(RefreshTokenTTL.Seconds()))
// set a new access token
accessToken := s.jwtIssuer.StringifyJwt(
s.jwtIssuer.MintToken(userId, s.jwtAudience.Name, AccessTokenTTL),
)
kit.SetHttpOnlyCookie(w, "accessToken", accessToken, int(AccessTokenTTL.Seconds()))
}
func SetHttpOnlyCookie(w http.ResponseWriter, name, value string, maxAge int) {
http.SetCookie(w, &http.Cookie{
Name: name,
Value: value,
HttpOnly: true,
MaxAge: maxAge,
})
}
下面是当用户请求API令牌时我访问Cookie的方式.处理程序调用GetTokenFromCookie()函数,如果返回错误,则返回401响应.错误是这种情况是"http:命名的Cookie不存在"
func GetHttpCookie(r *http.Request, name string) (*http.Cookie, error) {
return r.Cookie(name)
}
func GetTokenFromCookie(r *http.Request, name string) (jwt.Jwt, error) {
tokenCookie, err := GetHttpCookie(r, name)
if err != nil {
// DEBUG
log.Println(err)
return jwt.Jwt{}, err
}
return jwt.FromString(tokenCookie.Value)
}
在来自登录终结点的200响应之后,页面重定向到应用程序主页.在此页面上,向身份验证服务器发出请求,以接收用于连接实时聊天消息服务器的API令牌.正如您从身份验证服务器上的日志(log)输出中看到的,请求中没有收到访问令牌Cookie,因此请求返回401代码.
2023/05/19 02:33:57 GET [/jwtkeypub] - 200
2023/05/19 02:33:57 GET [/jwtkeypub] - 200
2023/05/19 02:34:23 POST [/login] - 200
2023/05/19 02:34:23 http: named cookie not present
{{ } { } []} http: named cookie not present
2023/05/19 02:34:23 GET [/apitokens?aud=MSGSERVICE] - 401
我认为问题出在我使用的是本地主机,而浏览器没有将cookie从本地主机:8080传输到本地主机:8081.我计划实现某种模拟身份验证,以避免读取开发环境的cookie来解决这个问题,但我不确定这是否是我的问题的真正原因.我只是想再看一眼,看看我能不能让它在不需要这样做的情况下工作.
更新:我已经查看了开发工具中的网络选项卡: 图像显示登录后的响应返回Cookie,但它们随后不会发送到端口8081上的身份验证服务器.我还查看了Cookie存储,在从登录获得200响应后,即使在响应中收到它们,也没有Cookie存在.我在私有模式下使用Firefox访问网站.请注意,即使我在GO代码中设置了MaxAge,Cookie中也不包含MaxAge,这似乎是一个问题.
更新:这是登录后的HAR文件.您可以看到响应具有Max-Age,但之后它不会显示在Cookie选项卡中.
{
"log": {
"version": "1.2",
"creator": {
"name": "Firefox",
"version": "113.0.1"
},
"browser": {
"name": "Firefox",
"version": "113.0.1"
},
"pages": [
{
"startedDateTime": "2023-05-19T12:16:37.081-04:00",
"id": "page_1",
"title": "Login Page",
"pageTimings": {
"onContentLoad": -8105,
"onLoad": -8077
}
}
],
"entries": [
{
"pageref": "page_1",
"startedDateTime": "2023-05-19T12:16:37.081-04:00",
"request": {
"bodySize": 31,
"method": "POST",
"url": "http://0.0.0.0:8081/login",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Host",
"value": "0.0.0.0:8081"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0"
},
{
"name": "Accept",
"value": "*/*"
},
{
"name": "Accept-Language",
"value": "en-US,en;q=0.5"
},
{
"name": "Accept-Encoding",
"value": "gzip, deflate"
},
{
"name": "Referer",
"value": "http://localhost:8080/"
},
{
"name": "Content-Type",
"value": "text/plain;charset=UTF-8"
},
{
"name": "Content-Length",
"value": "31"
},
{
"name": "Origin",
"value": "http://localhost:8080"
},
{
"name": "DNT",
"value": "1"
},
{
"name": "Connection",
"value": "keep-alive"
}
],
"cookies": [],
"queryString": [],
"headersSize": 370,
"postData": {
"mimeType": "text/plain;charset=UTF-8",
"params": [],
"text": "{\"username\":\"a\",\"password\":\"a\"}"
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Set-Cookie",
"value": "refreshToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJQMmY2RHg1RWxlYTF5THBUaVpEejBaS3Z1dk1FUkFPZEtBVGkwNDZSc2JNPSIsImF1ZCI6InN0ZWVsaXgiLCJpc3MiOiJzdGVlbGl4IiwiZXhwIjoiMTY4NTExNzc5NyIsImp0aSI6IjIwMUQzODZDNTRBQzlEOUMwRjdCODFBMDVDNDlFQTE1In0.SbxFgEAtZbh0zS-SXZmrVW9iLk-cFz6HcDMU0FHNl-K9BwCeb_boc5igEgImMSYK-NBVQZh1km7YknE-jkBWyF0rIYjSnTzjNUHHwMnn0jE1N-dtEfNRnF1OT0R2bxPSz8gmhtJ3B839xa-jh9uMPMkXEB8BYtABgPH1FqBdijHPUtRVKq6C3ulVleurp2eyF8EHpGLc9rr5wBYSFBk0HQ3FNjjUxfRQLDnzl2xYovoQ2em4grExnkdACxCSpXNtF5bQ7lCnEZyf7-CehrRNwZCpteGKj5ux_wrX_nxma3OEWwrlatML_j-e420TM1tub0C9Ymyt0bMugHw8vaiOGA; Max-Age=604800; HttpOnly"
},
{
"name": "Set-Cookie",
"value": "accessToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJQMmY2RHg1RWxlYTF5THBUaVpEejBaS3Z1dk1FUkFPZEtBVGkwNDZSc2JNPSIsImF1ZCI6InN0ZWVsaXgiLCJpc3MiOiJzdGVlbGl4IiwiZXhwIjoiMTY4NDUxNDE5NyIsImp0aSI6IjY2NjU1QjAyNTc4NkRBRTE1M0VDNDI3MzBGMjMxQ0FGIn0.cIs6KGjRGTHaWX_uFTts_V2a3YcBb7LA0jNOBTZeyDmpPQgRlcABnuYkWUIdjUdR6VYnDitFRV-XK2ZSq6Pk_ZgyfvJ3yRzvWGYjXMu7Nq7MLpVvUh9mLKSbKvlqunW6YVamHSCAbYS8-D_pY9fpWxIcXw0qbwA2XfTdzr0Mrw7ntrkdyK7O1QqWamnEHCmpLfJ2XJlQsU0KaD8FjkL76pO3lWmrca3VYnTmjP1Oo1HEhbK3nImtrNeL2khAyb8ns8ROj2HX41IDNK1aHWPfn9J04pgH3AfBfcwhhqZkrKjTVFQAkSYzuvjKPWOfpgYmBMw3Y5nG_PDf-zlvVPrdpQ; Max-Age=1200; HttpOnly"
},
{
"name": "Date",
"value": "Fri, 19 May 2023 16:16:37 GMT"
},
{
"name": "Content-Length",
"value": "0"
}
],
"cookies": [
{
"name": "refreshToken",
"value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJQMmY2RHg1RWxlYTF5THBUaVpEejBaS3Z1dk1FUkFPZEtBVGkwNDZSc2JNPSIsImF1ZCI6InN0ZWVsaXgiLCJpc3MiOiJzdGVlbGl4IiwiZXhwIjoiMTY4NTExNzc5NyIsImp0aSI6IjIwMUQzODZDNTRBQzlEOUMwRjdCODFBMDVDNDlFQTE1In0.SbxFgEAtZbh0zS-SXZmrVW9iLk-cFz6HcDMU0FHNl-K9BwCeb_boc5igEgImMSYK-NBVQZh1km7YknE-jkBWyF0rIYjSnTzjNUHHwMnn0jE1N-dtEfNRnF1OT0R2bxPSz8gmhtJ3B839xa-jh9uMPMkXEB8BYtABgPH1FqBdijHPUtRVKq6C3ulVleurp2eyF8EHpGLc9rr5wBYSFBk0HQ3FNjjUxfRQLDnzl2xYovoQ2em4grExnkdACxCSpXNtF5bQ7lCnEZyf7-CehrRNwZCpteGKj5ux_wrX_nxma3OEWwrlatML_j-e420TM1tub0C9Ymyt0bMugHw8vaiOGA"
},
{
"name": "accessToken",
"value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJQMmY2RHg1RWxlYTF5THBUaVpEejBaS3Z1dk1FUkFPZEtBVGkwNDZSc2JNPSIsImF1ZCI6InN0ZWVsaXgiLCJpc3MiOiJzdGVlbGl4IiwiZXhwIjoiMTY4NDUxNDE5NyIsImp0aSI6IjY2NjU1QjAyNTc4NkRBRTE1M0VDNDI3MzBGMjMxQ0FGIn0.cIs6KGjRGTHaWX_uFTts_V2a3YcBb7LA0jNOBTZeyDmpPQgRlcABnuYkWUIdjUdR6VYnDitFRV-XK2ZSq6Pk_ZgyfvJ3yRzvWGYjXMu7Nq7MLpVvUh9mLKSbKvlqunW6YVamHSCAbYS8-D_pY9fpWxIcXw0qbwA2XfTdzr0Mrw7ntrkdyK7O1QqWamnEHCmpLfJ2XJlQsU0KaD8FjkL76pO3lWmrca3VYnTmjP1Oo1HEhbK3nImtrNeL2khAyb8ns8ROj2HX41IDNK1aHWPfn9J04pgH3AfBfcwhhqZkrKjTVFQAkSYzuvjKPWOfpgYmBMw3Y5nG_PDf-zlvVPrdpQ"
}
],
"content": {
"mimeType": "text/plain",
"size": 0,
"text": ""
},
"redirectURL": "",
"headersSize": 1347,
"bodySize": 1748
},
"cache": {},
"timings": {
"blocked": 0,
"dns": 0,
"connect": 0,
"ssl": 0,
"send": 0,
"wait": 13,
"receive": 0
},
"time": 13,
"_securityState": "insecure",
"serverIPAddress": "0.0.0.0",
"connection": "8081"
}
]
}
}
The response appears to have the cookies, but they don't get saved.
并且对身份验证服务器的下一个请求没有添加任何Cookie.