我在聊天应用程序中遇到基于cookie的令牌认证问题。我使用Go后端和标准的网络库来向响应cookie添加令牌。当用户通过密码验证(通过POST到auth服务器上的/login路径)时,响应cookie应包含用于生成API令牌的访问令牌和用于重新生成访问令牌的刷新令牌。
下面是一个标记文件,其中包含我的开发环境中的应用程序服务的结构。每个服务器都在本地主机上使用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令牌。从auth服务器上的日志输出可以看出,请求中没有接收到访问令牌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
我认为问题在于我使用的是localhost,浏览器没有将cookie从localhost:8080传输到localhost:8081。我计划实施某种模拟认证,以避免阅读开发环境的cookie来解决这个问题,但我不确定这是否是我的问题的原因。只是想再看一眼,看看我能不能让它工作,而不需要这样做。
更新:我已经查看了开发工具中的网络选项卡:图像显示登录后的响应返回cookie,但它们随后不会发送到端口8081上的auth服务器。我也看过cookie存储后,得到200响应登录,有没有cookie目前,即使在收到他们的响应。我正在使用Firefox的私人模式访问该网站。请注意,cookie不包括MaxAge,即使我在Go代码中设置了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"
}
]
}
}
响应似乎有cookie,但它们不会被保存。
并且下一个对auth服务器的请求没有添加任何cookie。
1条答案
按热度按时间dced5bon1#
TL;DR:
0.0.0.0
和localhost
之间共享。1.会话cookie和普通cookie都可以在
http://localhost:8080
和http://localhost:8081
之间共享。1.从页面
http://localhost:8080/
发送到http://localhost:8081/
的请求被认为是跨域请求。fetch
发送的跨域请求应该使用credentials: 'include'
初始化,以使浏览器保存cookie。HAR显示网页的URL为
http://localhost:8080/
,但登录端点为http://0.0.0.0:8081/login
。0.0.0.0
的Cookie不会与localhost
共享。您可以运行下面的演示来观察行为:
1.运行demo:
go run main.go
;1.在浏览器中打开
http://localhost:8080/
。网页将做这些事情:1.它向
http://0.0.0.0:8081/login1
发送请求(目的是验证0.0.0.0
的cookie不会与localhost
共享;1.它向
http://localhost:8081/login2
发送请求(目的是验证会话cookie将在http://localhost:8080
和http://localhost:8081
之间共享;1.它向
http://localhost:8081/login3
发送请求(目的是验证http://localhost:8080
和http://localhost:8081
之间将共享正常cookie;1.它导航到
http://localhost:8080/resource
,服务器将转储请求。它显示此头被发送到服务器:Cookie: login2=localhost-session; login3=localhost
.注意事项:
credentials: 'include'
要求将Access-Control-Allow-Origin
头设置为精确的原点(即*
将被拒绝),将Access-Control-Allow-Credentials
头设置为true
。