如何将从DynamoDB获取的JWT令牌存入Cookie?(Serverless环境)
Alright, let's break this down step by step—here's exactly how to get that JWT stored in a cookie for your S3 static site, using Serverless Framework and your existing AWS setup:
First, you need to make sure your API Gateway and Lambda are set up to send the Set-Cookie header and handle cross-origin requests correctly (since your static site is on S3, it's a different origin from API Gateway).
Here's a snippet for your serverless.yml:
service: jwt-cookie-service provider: name: aws runtime: nodejs18.x stage: prod region: us-east-1 iam: role: statements: - Effect: Allow Action: - dynamodb:GetItem Resource: arn:aws:dynamodb:${self:provider.region}:${aws:accountId}:table/YourJWTTable # Replace with your table ARN functions: getJwt: handler: handler.getJwt events: - httpApi: path: /get-jwt method: get cors: allowedOrigins: - "https://your-s3-static-site-domain.com" # Replace with your S3 site's HTTPS domain allowedHeaders: - "Content-Type" - "Cookie" allowedMethods: - "GET" allowCredentials: true # Critical for cookies to work across origins
Next, update your Lambda function to fetch the JWT from DynamoDB, then construct the Set-Cookie header with secure attributes (to avoid XSS and CSRF risks).
Here's a Node.js example using AWS SDK v3:
const { DynamoDBClient, GetItemCommand } = require("@aws-sdk/client-dynamodb"); const { unmarshall } = require("@aws-sdk/util-dynamodb"); const client = new DynamoDBClient({ region: process.env.AWS_REGION }); exports.getJwt = async (event) => { // Fetch JWT from DynamoDB (adjust the key to match your table's schema) const params = { TableName: "YourJWTTable", Key: { userId: { S: "user123" } // Replace with your actual lookup key } }; const command = new GetItemCommand(params); const response = await client.send(command); const item = unmarshall(response.Item); const jwtToken = item.jwt; // Construct the Set-Cookie header const cookieHeader = [ `jwt=${jwtToken}`, `HttpOnly`, // Prevents JS access to the cookie (critical for XSS protection) `Secure`, // Only send over HTTPS (required for production) `SameSite=Strict`, // Mitigates CSRF risks `Domain=your-s3-static-site-domain.com`, // Match your S3 site's domain `Path=/`, // Apply cookie to entire site `Max-Age=${3600}` // Match your JWT's expiration (1 hour here) ].join("; "); return { statusCode: 200, headers: { "Set-Cookie": cookieHeader, "Access-Control-Allow-Origin": "https://your-s3-static-site-domain.com", // Match allowedOrigins in serverless.yml "Access-Control-Allow-Credentials": true }, body: JSON.stringify({ message: "JWT set in cookie" }) }; };
Your S3 bucket needs to allow cross-origin requests from your API Gateway domain, and permit credentials. Go to your S3 bucket's Permissions > CORS configuration and add this policy:
<CORSConfiguration> <CORSRule> <AllowedOrigin>https://your-api-gateway-domain.com</AllowedOrigin> <!-- Replace with your API Gateway domain --> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> <AllowCredentials>true</AllowCredentials> </CORSRule> </CORSConfiguration>
When your frontend makes a request to the API Gateway endpoint, it needs to include credentials so the browser saves the cookie. Here's an example with fetch:
fetch("https://your-api-gateway-domain.com/prod/get-jwt", { method: "GET", credentials: "include" // Critical: tells browser to send/receive cookies across origins }) .then(response => response.json()) .then(data => console.log("Cookie set successfully", data)) .catch(err => console.error("Error fetching JWT:", err));
- HTTPS is Mandatory: Modern browsers require
Securecookies to be sent only over HTTPS. Make sure both your API Gateway and S3 static site are using HTTPS (use CloudFront with S3 if needed, or custom domains with AWS Certificate Manager). - Domain Matching: The
Domainattribute in the cookie must exactly match your S3 static site's domain (no wildcards unless you're using a subdomain setup). - JWT Expiration: Align the
Max-Agein the cookie with your JWT'sexpclaim so they expire at the same time. - IAM Permissions: Double-check that your Lambda has permission to read from your DynamoDB table (the
serverless.ymlsnippet above includes this, but adjust the resource ARN to match your table).
内容的提问来源于stack exchange,提问作者WeCanBeFriends

