3 cookies httponly go express svelte
我有一个带有登录端点的 REST API。登录端点接受用户名和密码,服务器通过发送包含一些有效负载(如 JWT)的 HTTPOnly Cookie 进行响应。
我一直使用的方法已经工作了几年,直到上周Set-Cookie标题停止工作。在 REST API 失去功能之前,我没有接触过它的源代码,因为我当时正在开发基于 Svelte 的前端。
我怀疑这与本地主机中Secure设置的属性有关。false然而,根据使用HTTP cookies,只要是本地主机,不安全的连接就应该没问题。我以这种方式开发 REST API 一段时间了,很惊讶地发现 cookie 不再被设置。
使用 Postman 测试 API 会产生设置 cookie 的预期结果。
我尝试重新创建真实 API 的一般流程,并将其精简为核心要素。
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/golang-jwt/jwt/v4"
)
const idleTimeout = 5 * time.Second
func main() {
app := fiber.New(fiber.Config{
IdleTimeout: idleTimeout,
})
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Origin, Content-Type, Accept, Range",
AllowCredentials: true,
AllowMethods: "GET,POST,HEAD,DELETE,PUT",
ExposeHeaders: "X-Total-Count, Content-Range",
}))
app.Get("/", hello)
app.Post("/login", login)
go func() {
if err := app.Listen("0.0.0.0:8080"); err != nil {
log.Panic(err)
}
}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
_ = <-c
fmt.Println("\n\nShutting down server...")
_ = app.Shutdown()
}
func hello(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
}
func login(c *fiber.Ctx) error {
type LoginInput struct {
Email string `json:"email"`
}
var input LoginInput
if err := c.BodyParser(&input); err != nil {
return c.Status(400).SendString(err.Error())
}
stringUrl := fmt.Sprintf("https://jsonplaceholder.typicode.com/users?email=%s", input.Email)
resp, err := http.Get(stringUrl)
if err != nil {
return c.Status(500).SendString(err.Error())
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return c.Status(500).SendString(err.Error())
}
if len(body) > 0 {
fmt.Println(string(body))
} else {
return c.Status(400).JSON(fiber.Map{
"message": "Yeah, we couldn't find that user",
})
}
token := jwt.New(jwt.SigningMethodHS256)
cookie := new(fiber.Cookie)
claims := token.Claims.(jwt.MapClaims)
claims["purpose"] = "Just a test really"
signedToken, err := token.SignedString([]byte("NiceSecret"))
if err != nil {
// Internal Server Error if anything goes wrong in getting the signed token
fmt.Println(err)
return c.SendStatus(500)
}
cookie.Name = "access"
cookie.HTTPOnly = true
cookie.Secure = false
cookie.Domain = "localhost"
cookie.SameSite = "Lax"
cookie.Path = "/"
cookie.Value = signedToken
cookie.Expires = time.Now().Add(time.Hour * 24)
c.Cookie(cookie)
return c.Status(200).JSON(fiber.Map{
"message": "You have logged in",
})
}
Run Code Online (Sandbox Code Playgroud)
这基本上是通过 JSON 占位符的用户进行查找,如果找到具有匹配电子邮件地址的用户,则会发送 HTTPOnly Cookie 并附加一些数据。
考虑到这可能是我使用的库的问题,我决定用 Express 编写一个 Node 版本。
import axios from 'axios'
import express from 'express'
import cookieParser from 'cookie-parser'
import jwt from 'jsonwebtoken'
const app = express()
app.use(express.json())
app.use(cookieParser())
app.use(express.urlencoded({ extended: true }))
app.disable('x-powered-by')
app.get("/", (req, res) => {
res.send("Hello there!")
})
app.post("/login", async (req, res, next) => {
try {
const { email } = req.body
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/users?email=${email}`)
if (data) {
if (data.length > 0) {
res.locals.user = data[0]
next()
} else {
return res.status(404).json({
message: "No results found"
})
}
}
} catch (error) {
return console.error(error)
}
}, async (req, res) => {
try {
let { user } = res.locals
const token = jwt.sign({
user: user.name
}, "mega ultra secret sauce 123")
res
.cookie(
'access',
token,
{
httpOnly: true,
secure: false,
maxAge: 3600
}
)
.status(200)
.json({
message: "You have logged in, check your cookies"
})
} catch (error) {
return console.error(error)
}
})
app.listen(8000, () => console.log(`Server is up at localhost:8000`))
Run Code Online (Sandbox Code Playgroud)
这两个都不适用于我测试过的浏览器。
Go 对此做出回应。
HTTP/1.1 200 OK
Date: Mon, 21 Feb 2022 05:17:36 GMT
Content-Type: application/json
Content-Length: 32
Vary: Origin
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Total-Count,Content-Range
Set-Cookie: access=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdXJwb3NlIjoiSnVzdCBhIHRlc3QgcmVhbGx5In0.8YKepcvnMreP1gUoe_S3S7uYngsLFd9Rrd4Jto-6UPI; expires=Tue, 22 Feb 2022 05:17:36 GMT; domain=localhost; path=/; HttpOnly; SameSite=Lax
Run Code Online (Sandbox Code Playgroud)
对于 Node API,这是响应标头。
HTTP/1.1 200 OK
Set-Cookie: access=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiTGVhbm5lIEdyYWhhbSIsImlhdCI6MTY0NTQyMDM4N30.z1NQcYm5XN-L6Bge_ECsMGFDCgxJi2eNy9sg8GCnhIU; Max-Age=3; Path=/; Expires=Mon, 21 Feb 2022 05:13:11 GMT; HttpOnly
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: W/"34-TsGOkRa49turdlOQSt5gB2H3nxw"
Date: Mon, 21 Feb 2022 05:13:07 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Run Code Online (Sandbox Code Playgroud)
我用它作为发送和接收数据的测试表单。
HTTP/1.1 200 OK
Date: Mon, 21 Feb 2022 05:17:36 GMT
Content-Type: application/json
Content-Length: 32
Vary: Origin
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Total-Count,Content-Range
Set-Cookie: access=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdXJwb3NlIjoiSnVzdCBhIHRlc3QgcmVhbGx5In0.8YKepcvnMreP1gUoe_S3S7uYngsLFd9Rrd4Jto-6UPI; expires=Tue, 22 Feb 2022 05:17:36 GMT; domain=localhost; path=/; HttpOnly; SameSite=Lax
Run Code Online (Sandbox Code Playgroud)
邮递员: 9.8.3
去: 1.17.6
Node.js: v16.13.1
苗条: 3.44.0
火狐浏览器: 97.0.1
微软边缘: 98.0.1108.56
铬: 99.0.4781.0
小智 8
事实证明问题出在前端,特别是 JavaScript 的fetch()方法。
let response = await fetch(`http://localhost:8000/login`, {
method: "POST",
credentials: "include", //--> send/receive cookies
body: JSON.stringify({
email,
}),
headers: {
"Content-Type": "application/json",
},
});
Run Code Online (Sandbox Code Playgroud)
您的对象中需要credentials: include属性RequestInit,不仅用于发出需要 cookie 身份验证的请求,还用于接收所述 cookie。
Axios 通常会自动填写这部分(根据经验),但如果没有,您还需要添加请求的withCredentials: true第三个config参数以允许浏览器设置 cookie。
| 归档时间: |
|
| 查看次数: |
15145 次 |
| 最近记录: |