Saya menghadapi masalah dengan pengesahan token berasaskan kuki dalam aplikasi sembang. Saya menggunakan go backend dengan perpustakaan rangkaian standard untuk menambahkan token pada kuki respons. Apabila pengguna disahkan kata laluan (melalui catatan ke laluan /login pada pelayan pengesahan), kuki respons harus mengandungi token akses yang digunakan untuk menjana token api dan token muat semula yang digunakan untuk menjana semula token akses.
Ini ialah fail markup yang mengandungi struktur perkhidmatan aplikasi dalam persekitaran pembangunan saya. Setiap pelayan berjalan pada localhost menggunakan go net/http pada port berjujukan (perkhidmatan yang tidak berkaitan tidak ditunjukkan).
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" )
Ini adalah kod untuk menetapkan kuki semasa log masuk. Ini berlaku selepas semakan kata laluan
// 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, }) }
Berikut ialah cara saya mengakses kuki apabila pengguna meminta token api. Jika ralat dikembalikan, pengendali memanggil fungsi gettokenfromcookie() dan bertindak balas dengan 401. Ralat dalam kes ini ialah "http: Kuki bernama tidak wujud"
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) }
Selepas 200 respons daripada titik akhir log masuk, halaman itu diubah hala ke halaman aplikasi utama. Pada halaman ini, buat permintaan kepada pelayan pengesahan untuk menerima token API yang digunakan untuk menyambung ke pelayan pemesejan sembang langsung. Seperti yang anda boleh lihat daripada output log pada pelayan auth, kuki token akses tidak diterima dengan permintaan, jadi permintaan itu mengembalikan kod 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
Saya percaya masalahnya ialah saya menggunakan localhost dan penyemak imbas tidak memindahkan kuki dari locahost:8080 ke localhost:8081. Saya bercadang untuk melaksanakan beberapa jenis pengesahan penyamaran yang memintas membaca kuki persekitaran pembangunan untuk menyelesaikan masalah ini, tetapi saya tidak pasti sama ada itu sebenarnya punca masalah saya. Hanya mahu melihat sekali lagi dan melihat sama ada saya boleh membuatnya berfungsi tanpa perlu melakukan ini.
Kemas kini: Saya telah melihat tab rangkaian dalam alat pembangun: Imej menunjukkan bahawa respons selepas log masuk mengembalikan kuki, tetapi ia tidak kemudiannya dihantar ke pelayan pengesahan pada port 8081. Selepas mendapat respons 200 untuk log masuk saya juga melihat storan kuki dan walaupun selepas itu tiada kuki yang menerimanya dalam respons. Saya menggunakan mod peribadi firefox untuk mengakses tapak. Ambil perhatian bahawa walaupun saya menetapkan maxage dalam kod go, kuki tidak mengandungi maxage, yang nampaknya menjadi isu.
Kemas kini: Ini ialah fail har selepas log masuk. Anda boleh melihat bahawa respons mempunyai umur maksimum, tetapi kemudian ia tidak muncul dalam tab kuki.
{ "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" } ] } }
Respons nampaknya mempunyai kuki, tetapi ia tidak disimpan.
Dan permintaan seterusnya kepada pelayan pengesahan tidak menambah sebarang kuki.
tl;dr:
0.0.0.0
和 localhost
. http://localhost:8080
和 http://localhost:8081
. http://localhost:8080/
页面发送到 http://localhost:8081/
akan dianggap sebagai permintaan silang asal. fetch
发送的跨域请求应使用 credentials: 'include'
Mulakan supaya penyemak imbas menyimpan kuki. har memaparkan url halaman web untuk http://localhost:8080/
,但登录端点为http://0.0.0.0:8081/login
。 0.0.0.0
的 cookie 不会与 localhost
perkongsian.
Anda boleh menjalankan demo di bawah untuk memerhati tingkah laku:
Jalankan demo: go run main.go
;
Buka dalam pelayarhttp://localhost:8080/
. Halaman ini akan melakukan perkara berikut:
http://0.0.0.0:8081/login1
发送请求(目的是验证0.0.0.0
的cookie不会与localhost
;
http://localhost:8081/login2
(tujuannya adalah untuk mengesahkan bahawa kuki sesi akan dikongsi antara http://localhost:8081/login2
发送请求(目的是验证会话 cookie 将在 http://localhost:8080
和 http://localhost:8081
http://localhost:8081/login3
发送请求(目的是验证正常的cookie将在http://localhost:8080
和http://localhost:8081
http://localhost:8080/resource
并且服务器将转储请求。表明这个头被发送到服务器:cookie:login2=localhost-session; login3=localhost
Nota: . credentials: 'include'
要求将 access-control-allow-origin
标头设置为确切的来源(这意味着 *
将被拒绝),并且 access- control-allow-credentials
标头设置为 true
package main import ( "fmt" "log" "net/http" "net/http/httputil" ) func setHeader(w http.ResponseWriter, cookieName, cookieValue string, maxAge int) { w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8080") w.Header().Set("Access-Control-Allow-Credentials", "true") http.SetCookie(w, &http.Cookie{ Name: cookieName, Value: cookieValue, MaxAge: maxAge, HttpOnly: true, }) } func main() { muxWeb := http.NewServeMux() // serve the HTML page. muxWeb.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write([]byte(page)) if err != nil { panic(err) } })) // Dump the request to see what cookies is sent to the server. muxWeb.Handle("/resource", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { dump, err := httputil.DumpRequest(r, false) if err != nil { panic(err) } _, _ = w.Write(dump) })) web := &http.Server{ Addr: ":8080", Handler: muxWeb, } go func() { log.Fatal(web.ListenAndServe()) }() muxAPI := http.NewServeMux() muxAPI.Handle("/login1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { setHeader(w, "login1", "0.0.0.0", 1200) })) muxAPI.Handle("/login2", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { setHeader(w, "login2", "localhost-session", 0) })) muxAPI.Handle("/login3", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { setHeader(w, "login3", "localhost", 1200) })) api := &http.Server{ Addr: ":8081", Handler: muxAPI, } go func() { log.Fatal(api.ListenAndServe()) }() fmt.Println("Open http://localhost:8080/ in the browser") select {} } var page string = ` <!DOCTYPE html> <html> <body> <script type="module"> async function login(url) { const response = await fetch(url, { mode: 'cors', credentials: 'include', }); } await login('http://0.0.0.0:8081/login1'); await login('http://localhost:8081/login2'); await login('http://localhost:8081/login3'); window.location = '/resource'; </script> </body> </html> `
Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan kuki tidak dipindahkan antara port localhost dalam aplikasi sembang Go?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!