问题描述
我是节点上的新手,我有一个带有express的rest api,并且某些端点使用keycloak-connect具有keycloak安全性。当发生错误403时,我需要一个自定义响应,即json格式的自定义消息。我使用处理程序来管理其他一些状态,例如200、201、204、404、500,但是当密钥斗篷抛出403时我无法工作。
var memoryStore = new session.MemoryStore();
app.use(session({
secret: 'my-secret',resave: false,saveUninitialized: true,store: memoryStore
}));
var keycloak = new Keycloak({
store: memoryStore
});
app.use(keycloak.middleware());
// keycloak security
app.get('/service/secured',keycloak.protect('realm:user'),function (req,res) {
res.json({message: 'secured'});
});
app.get('/service/admin',keycloak.protect('realm:admin'),res) {
res.json({message: 'admin'});
});
// 404 handler and pass to error handler
app.use((req,res,next) => {
next(createError(404,'Not found'));
});
// Error Handler
app.use((err,req,next) => {
// This log never is printed when 403 ocurrs
console.log('Error: ',err);
res.status(err.status || 500);
res.send({
error : {
status : err.status || 500,message : err.message
}
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT,() => {
console.log(`Server starter on port ${PORT}`);
});
解决方法
问题是keycloak-connect使用了express中间件错误。它使用 res.end()
代替 next()
,因此在此之后您什么也做不了。您可以尝试通过添加新的中间件来重写此逻辑。
...
app.use(function(req,res,next) {
res.end = function(body) {
if (res.statusCode === 403 && body === 'Access denied') {
next(body);
} else {
res.send(body);
}
}
});
app.use(keycloak.middleware());
...
// handle error how you want
,
您可以在初始化之前覆盖 Keycloak.prototype.accessDenied
并抛出新错误以便您的句柄可以处理。
var memoryStore = new session.MemoryStore();
app.use(session({
secret: 'my-secret',resave: false,saveUninitialized: true,store: memoryStore
}));
// Overriding keycloak access denied to return 401 status code and custom message.
Keycloak.prototype.accessDenied = () => {
// Considering createError will throw new Error.
createError(401,'Access Denied');
};
var keycloak = new Keycloak({
store: memoryStore
});
app.use(keycloak.middleware());
// keycloak security
app.get('/service/secured',keycloak.protect('realm:user'),function (req,res) {
res.json({message: 'secured'});
});
app.get('/service/admin',keycloak.protect('realm:admin'),res) {
res.json({message: 'admin'});
});
// 404 handler and pass to error handler
app.use((req,next) => {
next(createError(404,'Not found'));
});
// Error Handler
app.use((err,req,next) => {
// Now this print with error 401 and message Access Denied
console.log('Error: ',err);
res.status(err.status || 500);
res.send({
error : {
status : err.status || 500,message : err.message
}
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT,() => {
console.log(`Server starter on port ${PORT}`);
});