我正在研究一个具有完整MEAN堆栈的大学/学生项目。我们有NodeJS,ExpressJS后端和Angular2前端。后端在localhost:8080
上运行,前端在localhost:4200
上运行
这就是我后端的样子
var express = require('express'),
...
var app = express();
...
// needed because of cross origin resource sharing during development
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
var port = process.env.PORT || 8080;
var loginController = require('./controllers/loginController')(Person);
var personController = require('./controllers/personController')(Person, Transaction);
var transactionController = require('./controllers/transactionController')(Person, Transaction);
var apiRouter = express.Router();
apiRouter.post('/login', loginController.authenticate);
/**
* Middleware that handles authorization of particular routes.
* Every request which starts with `/api/persons` or `/api/transactions`, will be intercepted and validated against JWT.
*/
apiRouter.use(function (req, res, next) {
// JWT gets validated
});
apiRouter.get('/persons', personController.fetchAllPersons);
apiRouter.get('/persons/:personId', personController.fetchPersonById);
apiRouter.get('/persons/:personId/transactions', personController.fetchTransactionsByPersonId);
apiRouter.post('/transactions', transactionController.addNewTransaction);
app.use('/api', apiRouter);
app.listen(port, function () {
console.log('Listening on port: ' + port);
});
我读到快递路由器的路由按顺序执行,因此中间件包含的顺序很重要。因此我在/login
路由之后设置它,因为没有JWT授权它不应该可用。
当我启动应用程序并使用postman
执行请求时,一切都按预期工作,但是当我尝试从前端登录中间件时,也会执行登录路由,但它不应该,对吧?
可能是因为他们在不同的端口上运行,或者它可能是由交叉起源引起的问题,我真的不知道? 有没有人已经面临类似的问题,你能解释一下这种行为吗? THX
编辑1:
正如robertklep在下面提到的,它可能取决于loginController实现以及我们如何处理前端登录的方式,这里是代码片段
jwt = require('jsonwebtoken');
var loginController = function (Person) {
var authenticate = function (req, res) {
req.person = req.body;
var searchPerson = { username: req.person.username }
Person.findOne(searchPerson, function (err, person) {
if (err) throw err;
if (!person) {
return res.status(401).send({ message: 'Wrong username/password' });
}
person.comparePasswords(req.person.password, function (err, isMatch) {
if (err) throw err;
if (!isMatch) {
return res.status(401).send({ message: 'Wrong username/password' });
}
var token = jwt.sign(person._id, /* XXX SECRET XXX */);
res.status(200).json({
token: token,
person: person
});
});
});
};
return {
authenticate: authenticate
};
};
module.exports = loginController;
前端:
...
export class LoginComponent implements OnInit {
/**
* validates input data and on successful validation,
* tries to login the user with her/his credentials
*/
public login(): void {
// validation logic should consider all fields, no matter if the user has entered any data
this.validate(false);
// no validation error, continue with login process
if(!this.errorMessage){
const form = this.loginForm;
var credentials = {
name: form.get('name').value,
password: form.get('password').value
};
this.loginService.login(credentials.name,credentials.password)
.subscribe(
name => this.router.navigate(['welcome']),
error => this.errorMessage = error);
}
}
}
...
export class LoginService {
...
public login(userName: string, password: string): Observable<string> {
var person = {
'username': userName,
'password': password
};
return this.http.post('http://localhost:8080/api/login',person)
.map(this.extractToken)
.catch(this.handleError);
}
}
编辑2:
据我所知,我发布了我的中间件,所以这就是它的样子
apiRouter.use(function(req, res, next) {
// first, check if a token is provided
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
// token gets validated by jwt lib
jwt.verify(token, /* SECRET */, function (err, decoded) {
if (err) {
// token invalid, respond with unauthorized
res.status(401).json({
message: 'Failed to authenticate token.'
});
} else {
// token is valid, continue to the particular request handler
req.decoded = decoded;
next();
}
});
} else {
// token was not provided, respond with forbidden
res.status(403).json({
message: 'No token provided.'
});
}
});
就像我说的,当我使用postman客户端并执行登录请求时,一切都按预期工作(中间件不会执行登录请求)但是当我启动我们的前端应用程序并执行相同操作时,中间件函数会被执行