如何在Parse-Server日志中查看登录失败请求的源IP地址?
Hey Lukas, tracking source IPs for failed login attempts is such a crucial part of monitoring account attacks—totally get why this matters to you. Here are a few practical ways to add this logging without touching the Parse-Server core code:
1. Use a Custom Login Cloud Function
This gives you full control over the login flow and direct access to the request object (including source IP). You’ll just need to update your client-side code to call this custom function instead of the default logIn method.
Here’s a sample implementation:
Parse.Cloud.define("customLogin", async (request) => { const { username, password } = request.params; const sourceIP = request.ip; // Grab the source IP directly from the request try { // Execute the standard login logic const user = await Parse.User.logIn(username, password); return user; // Return the user object to the client as usual } catch (error) { // Log the failed attempt with IP and username console.error(`Failed login attempt | IP: ${sourceIP} | Username: ${username} | Error: ${error.message}`); // Re-throw the error so the client gets the standard failure response throw error; } });
Pros: Reliable, easy to implement, and you can add extra validation or logging logic if needed.
Cons: Requires updating client code to use customLogin instead of the built-in Parse.User.logIn().
2. Add an Express Global Error Middleware
Since Parse-Server runs on top of Express, you can attach a custom error-handling middleware to catch login failure errors and log the source IP. This works with the default login flow, so no client-side changes are needed.
Example code for your Express app setup:
const express = require('express'); const ParseServer = require('parse-server').ParseServer; const Parse = require('parse/node'); const app = express(); const parseServerConfig = { databaseURI: "your-db-uri", appId: "your-app-id", masterKey: "your-master-key", // ... other Parse-Server configs }; // Mount Parse-Server to your Express app app.use('/parse', new ParseServer(parseServerConfig)); // Global error-handling middleware app.use((err, req, res, next) => { // Check if this is a Parse login failure error (code 101 = invalid username/password) if (err instanceof Parse.Error && err.code === 101) { const sourceIP = req.ip; // Extract username/email from the login request body const username = req.body?.username || req.body?.email || "unknown"; // Log the detailed failure console.error(`Login failed | IP: ${sourceIP} | Username/Email: ${username} | Error: ${err.message}`); } // Pass the error along so Parse-Server can send the standard response to the client next(err); }); app.listen(1337, () => { console.log('Parse-Server running on http://localhost:1337/parse'); });
Pros: No client changes required, works with the default login endpoint.
Cons: Relies on parsing the request body and checking the error code—make sure to test if the request format matches your Parse-Server version.
3. Combine beforeLogin Trigger with Error Logging (Alternative)
You can use the beforeLogin cloud trigger to capture the source IP before the login attempt, then pair it with a global error handler to log failures. This is a bit more involved but avoids client changes:
// Capture IP in beforeLogin trigger and attach it to the request context Parse.Cloud.beforeLogin(async (user, context) => { const sourceIP = context.request.ip; // Attach IP to the request object for later use in error handling context.request.loginAttemptIP = sourceIP; }); // Then in your Express error middleware: app.use((err, req, res, next) => { if (err instanceof Parse.Error && err.code === 101 && req.loginAttemptIP) { const username = req.body?.username || req.body?.email || "unknown"; console.error(`Login failed | IP: ${req.loginAttemptIP} | Username/Email: ${username} | Error: ${err.message}`); } next(err); });
Pros: No client changes, captures IP early in the flow.
Cons: Requires ensuring the beforeLogin trigger runs before the error is thrown, and depends on the context object exposing the request (check your Parse-Server version for this support).
内容的提问来源于stack exchange,提问作者Lukas Futera

