#node.js #keycloak #keycloak-rest-api
#node.js #keycloak #keycloak-rest-api
Вопрос:
Я новичок в node, у меня есть rest api с express, а некоторые конечные точки имеют защиту от скрытого доступа с использованием keycloak-connect. Мне нужен пользовательский ответ при обнаружении ошибки 403, то есть пользовательское сообщение в формате json. Я использую обработчик для управления каким-либо другим статусом, например, 200, 201, 204, 404, 500, но я не смог выполнить работы, когда keycloak выдает 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'), function (req, 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, res, 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}`);
});
Ответ №1:
Проблема в том, что keycloak-connect неправильно использует промежуточное программное обеспечение express. Оно использует res.end()
вместо next()
, поэтому вы ничего не можете сделать после этого. Вы можете попробовать переписать эту логику, добавив новое промежуточное программное обеспечение.
...
app.use(function(req, res, next) {
res.end = function(body) {
if (res.statusCode === 403 amp;amp; body === 'Access denied') {
next(body);
} else {
res.send(body);
}
}
});
app.use(keycloak.middleware());
...
// handle error how you want
Комментарии:
1. Запрос просто истекает. Как мне вернуть пользовательский объект ответа вместо
Access denied
текста по умолчанию2. @odane-brissett У вас есть обработчик ошибок маршрутизатора? expressjs.com/en/guide/error-handling.html Вот так:
app.use(function (err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); });
Ответ №2:
Вы можете переопределить 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'), function (req, 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, res, 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}`);
});