单数据库下多站点(WS1/WS2)的身份认证与安全配置咨询
Hey there! Let's break down your problem step by step—this is a super common scenario when building multiple related sites, so we’ve got solid patterns to balance shared data, isolation, and security.
The key here is to keep your common information accessible to both sites while walling off user accounts, sessions, and permissions completely. You don’t need to overcomplicate things with separate databases or full framework deployments right away.
1. Database Architecture: Split Collections, Not Databases (For Now)
Instead of creating two separate ArangoDB instances, use isolated collections within a single database (you can split into separate databases later if needed for compliance or scale):
- Shared Collections: Create collections like
shared_articles,public_products, orcommon_settingsfor data both sites need access to. - Site-Specific Collections: For each site, create dedicated collections for users and permissions, e.g.:
ws1_users+ws1_permissionsws2_users+ws2_permissions
This approach avoids duplicate data, keeps queries simple, and prevents accidental cross-site data leaks. If you later need full database-level isolation, moving these collections to separate databases is straightforward.
2. Express Deployment: One Instance with Isolated Logic
You don’t need to deploy a separate Express framework for each Nginx server block. Two clean options:
Option A: Single App with Site Identification Middleware
Add a middleware at the top of your Express app to tag requests with the site ID, then use that tag to route to the right auth/data logic:
// Identify the site from the request hostname app.use((req, res, next) => { const validSites = { 'ws1.yourdomain.com': 'ws1', 'ws2.yourdomain.com': 'ws2' }; req.siteId = validSites[req.hostname]; // Reject requests for unknown domains if (!req.siteId) { return res.status(403).send('Invalid site'); } next(); }); // Example login route that uses the site ID app.post('/api/login', async (req, res) => { // Query the site-specific user collection const user = await arango.db.collection(`${req.siteId}_users`).findOne({ email: req.body.email }); // Validate credentials, create session, etc.—all tied to ws1/ws2 });
Option B: Mounted Sub-Apps for Clean Isolation
If you want stricter code separation, create two Express sub-apps for each site and mount them based on the hostname:
const ws1App = express(); const ws2App = express(); // Configure ws1-specific auth middleware and routes ws1App.use(ws1AuthMiddleware); ws1App.get('/api/profile', ws1ProfileRoute); // Configure ws2-specific auth middleware and routes ws2App.use(ws2AuthMiddleware); ws2App.get('/api/profile', ws2ProfileRoute); // Main app routes requests to the correct sub-app app.use((req, res, next) => { if (req.hostname === 'ws1.yourdomain.com') { ws1App(req, res, next); } else if (req.hostname === 'ws2.yourdomain.com') { ws2App(req, res, next); } else { res.status(403).send('Invalid site'); } });
Both options let you share common code (like shared data queries) while keeping auth logic isolated.
3. Security Measures to Block Cross-Site Access
To ensure users from one site can’t access the other:
- Isolate Sessions: Use unique cookie names for each site (e.g.,
ws1_session_idandws2_session_id) and set thedomaincookie attribute to the respective site’s domain. For JWT, add asiteIdclaim to the token and validate it on every request—reject tokens where thesiteIddoesn’t match the current request’s site. - Strict Host Validation: In Nginx, add a check in each server block to reject requests with mismatched host headers:
# For WS1 server block if ($host != 'ws1.yourdomain.com') { return 444; # Close connection immediately } - Bind Permissions to Site ID: When checking user permissions, always filter by the current
siteId—never fetch permissions without it. For example, don’t just querypermissionsbyuserId; query byuserIdANDsiteId. - Hardened Headers: Add security headers in Nginx to prevent cross-site exploits:
add_header X-Frame-Options SAMEORIGIN; add_header Content-Security-Policy "default-src 'self'"; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
4. Best Practices to Keep Things Scalable
- Start with Collections, Split Databases Later: Using isolated collections is simpler initially. Only split into separate databases if you hit compliance requirements, performance limits, or need complete data separation.
- Share Common Utilities: Create a shared module for querying public data, so you don’t duplicate code across site-specific routes.
- Test Cross-Site Scenarios: Intentionally try to use a WS1 user’s session on WS2, or query WS2’s user data from WS1—make sure these requests are rejected.
- Log with Site ID: Include the
siteIdin all logs to easily debug issues across both sites.
Hope this gives you a clear path forward! Let me know if you need deeper details on any of these steps.
内容的提问来源于stack exchange,提问作者user7552709

