Доступ запрещен в js-приложении keycloak.protect() Express node

Я пытаюсь получить информацию о пользователе из keycloak с помощью промежуточного программного обеспечения keycloak.protect(), но всегда получаю 403 «Доступ запрещен».

Клавиатура версии 24.0.2

Я сделал свое собственное царство и клиента

Мой keycloak.json

{
  "realm": "realm",
  "auth-server-url": "http://localhost:8080/",
  "bearerOnly": true,
  "ssl-required": "external",
  "resource": "tender",
  "verify-token-audience": true,
  "credentials": {
    "secret": "some secret"
  },
  "use-resource-role-mappings": true,
  "confidential-port": 0,
  "policy-enforcer": {
    "credentials": {}
  }
}

index.js

const app: Express = express();
app.use(cors());
app.use(express.json());

app.use(
  session({
    secret: "mySecret",
    resave: false,
    saveUninitialized: true,
    store: memoryStore,
  })
);

app.use(
  keycloak.middleware({
    logout: "/logout",
    admin: "/",
  })
);

app.use("/api/v1", router);

const port = process.env.PORT || 3000;

const start = async () => {
  try {
    await sequelize.authenticate();
    await sequelize.sync();
    app.listen(port, () => {
      console.info(`[server]: Server is running at http://localhost:${port}`);
    });
  } catch (error) {
    console.info(error);
  }
};

start();
router.post("/login", userController.login);
router.get("", keycloak.protect(), userController.get);

Вход работает. Я получаю токены, но get маршрут всегда возвращает «Доступ запрещен». Что мне следует сделать в консоли администратора, чтобы решить эту проблему?

Я пробовал играть с ролями в консоли администратора, но это не помогло.

Где вы используете keycloak. На удаленном экземпляре? В Docker или через бинарный файл?

Mocktar Issa 03.04.2024 14:35

Докер @MocktarIssa

user23984730 04.04.2024 03:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
315
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам необходимо включить и настроить службы авторизации в Keycloak. Это включает в себя настройку политик, разрешений, ресурсов и областей.

Resources: вещи, которые вы хотите защитить, например API, веб-страницы или любой другой ресурс. Это цель API.

Scopes: Это действие, например чтение, запись или удаление, выполняемое над ресурсом.

Permission: связь между ресурсами и областью действия. Он решает разрешить или запретить доступ к ресурсу.

Policy: Определите условия, при которых предоставляется доступ к ресурсу.

Демо

Я воспользуюсь keycloak-nodejs-connectпримером

Я покажу, что имя пользователя user — это ошибка 403, но имя пользователя admin не является ошибкой Access granted to Default Resource.

user

admin

Есть много шагов, Пожалуйста, следуйте за мной шаг за шагом.

Шаг 1. Запуск Keycloak v24.2

В здесь

Шаг 2. Импортируйте nodejs-example область.

{
    "realm": "nodejs-example",
    "enabled": true,
    "sslRequired": "external",
    "registrationAllowed": true,
    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y = ",
    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
    "requiredCredentials": [ "password" ],
    "users" : [
        {
            "username" : "user",
            "enabled": true,
            "email" : "sample-user@nodejs-example",
            "firstName": "Sample",
            "lastName": "User",
            "credentials" : [
                { "type" : "password",
                  "value" : "password" }
            ],
            "realmRoles": [ "user" ],
            "clientRoles": {
                "account": ["view-profile", "manage-account"]
            }
        }
    ],
    "roles" : {
        "realm" : [
            {
                "name": "user",
                "description": "User privileges"
            },
            {
                "name": "admin",
                "description": "Administrator privileges"
            }
        ]
    },
    "scopeMappings": [
        {
            "client": "nodejs-connect",
            "roles": ["user"]
        }
    ],
    "clients": [
        {
            "clientId": "nodejs-connect",
            "enabled": true,
            "publicClient": true,
            "baseUrl": "/",
            "adminUrl" : "http://localhost:3000/",
            "baseUrl" : "http://localhost:3000/",
            "redirectUris": [
                "http://localhost:3000/*"
            ],
            "webOrigins": []
        },
        {
            "clientId": "nodejs-apiserver",
            "enabled": true,
            "secret": "secret",
            "redirectUris": [
              "http://localhost:3000/*"
            ],
            "webOrigins": [
              "http://localhost:3000/*"
            ],
            "serviceAccountsEnabled": true,
            "authorizationServicesEnabled": true,
            "authorizationSettings": {
              "resources": [
                {
                  "name": "resource",
                  "type": "urn:nodejs-apiserver:resources:default",
                  "ownerManagedAccess": false,
                  "uris": [
                    "/*"
                  ],
                  "scopes": [
                    {
                      "name": "view"
                    },
                    {
                      "name": "write"
                    }
                  ]
                }
              ]
            }
          }
    ]
}

Результат импорта области nodejs-example

В клиенте nodejs-apiserver по умолчанию есть resource с областями действия write и view.

Я покажу, что к этому ресурсу может получить доступ пользователь admin.

Шаг 3. Добавьте пользователя admin

пароль 1234

Шаг 4. Настройте политику

Результат политики установки

Шаг 5. Настройте разрешение

Результат разрешения на установку

Шаг 6. Настройка сервера

Дерево файлов

Сохранить как index.html в каталоге view

<html>
<head>
    <style>
        ul {
            list-style-type: none;
            margin: 0;
            padding: 0;
            background-color: #f1f1f1;
        }

        li a {
            display: block;
            color: #000;
            padding: 8px 0 8px 16px;
            text-decoration: none;

        }

        /* Change the link color on hover */
        li a:hover {
            background-color: #555;
            color: white;
        }

        .nav {
            float: left;
            width: 250px;
        }
        .content {
            margin-left: 270px;

        }
        pre {
            word-wrap: break-word;
            white-space: pre-wrap;
            background-color: #ddd;
            border: 1px solid #ccc;
            padding: 20px;
        }
    </style>
</head>
<body>

<h1 style = "width: 100%; text-align: center;">NodeJS Keycloak Example</h1>
<hr/>

<div class = "nav">
    <ul>
        <li><a href = "/login">Login</a></li>
        <li><a href = "/protected/resource">Protected Resource</a></li>
        <li><a href = "/logout">Logout</a></li>
    </ul>
</div>
<div class = "content">
    <h2>Result</h2>
    <pre id = "output">
{{result}}
    </pre>

    <h2>Events</h2>
    <pre id = "events">
{{event}}
    </pre>
</div>


</body>
</html>

Сохранить как server.js

const Keycloak = require('keycloak-connect')
const hogan = require('hogan-express')
const express = require('express')
const session = require('express-session')

const app = express()

const server = app.listen(3000, function () {
  const host = server.address().address
  const port = server.address().port
  console.info('Example app listening at http://%s:%s', host, port)
})

// Register '.mustache' extension with The Mustache Express
app.set('view engine', 'html')
app.set('views', require('path').join(__dirname, '/view'))
app.engine('html', hogan)

// A normal un-protected public URL.

app.get('/', function (req, res) {
  res.render('index')
})

// Create a session-store to be used by both the express-session
// middleware and the keycloak middleware.

const memoryStore = new session.MemoryStore()

app.use(session({
  secret: 'mySecret',
  resave: false,
  saveUninitialized: true,
  store: memoryStore
}))

// Provide the session store to the Keycloak so that sessions
// can be invalidated from the Keycloak console callback.
//
// Additional configuration is read from keycloak.json file
// installed from the Keycloak web console.

const keycloak = new Keycloak({
  store: memoryStore
})

// Install the Keycloak middleware.
//
// Specifies that the user-accessible application URL to
// logout should be mounted at /logout
//
// Specifies that Keycloak console callbacks should target the
// root URL.  Various permutations, such as /k_logout will ultimately
// be appended to the admin URL.

app.use(keycloak.middleware({
  logout: '/logout',
  admin: '/',
  protected: '/protected/resource'
}))

app.get('/login', keycloak.protect(), function (req, res) {
  res.render('index', {
    result: JSON.stringify(JSON.parse(req.session['keycloak-token']), null, 4),
    event: '1. Authentication\n2. Login'
  })
})

app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
  resource_server_id: 'nodejs-apiserver'
}), function (req, res) {
  res.render('index', {
    result: JSON.stringify(JSON.parse(req.session['keycloak-token']), null, 4),
    event: '1. Access granted to Default Resource\n'
  })
})

package.json

{
  "name": "nodejs-keycloak-example",
  "version": "0.1.0",
  "description": "Example page that demonstrates available keycloak functionality",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "Roman Jurkov <[email protected]>",
  "license": "Apache-2.0",
  "dependencies": {
    "express": "^4.19.2",
    "express-session": "^1.18.0",
    "hogan-express": "^0.5.2",
    "keycloak-connect": "^24.0.2"
  }
}

Шаг 7. Установите зависимости и запустите.

npm install
node index.js

Шаг 8. Открыть в браузере

http://localhost:3000

Шаг 9. 403 Ошибка для пользователя

Полномочия

username: user
password: password

Результат

Шаг 10. Предоставление доступа для admin

Полномочия

username: admin
password: 1234

Результат

Пользователь admin может получить доступ resource без ошибок.

Этот код передан и отобразил сообщение Access granted в формате html.

app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
  resource_server_id: 'nodejs-apiserver'
}), function (req, res) {
  res.render('index', {
    result: JSON.stringify(JSON.parse(req.session['keycloak-token']), null, 4),
    event: '1. Access granted to Default Resource\n'
  })
})

Заключение

Таким образом, ваш «тендерный» ресурс должен настроить политику/разрешения для вашего конкретного пользователя.

Это было действительно полезно, но мне нужно использовать keycloak без пользовательского интерфейса (только серверная часть), процесс тот же?

user23984730 04.04.2024 09:35

а также не могли бы вы показать, как получить атрибуты пользователя после промежуточного программного обеспечения?

user23984730 04.04.2024 09:50

keycloak-nodejs-connect служит промежуточным программным обеспечением, использующим поток кода аутентификации, который предназначен для сценариев, когда пользователь входит в систему через пользовательский интерфейс. Процесс не тот. Я рекомендую использовать вызов REST API из бэкэнда вместо использования keycloak-nodejs-connect. Вы можете получить атрибуты пользователя путем декодирования токена в здесь

Bench Vue 04.04.2024 12:28

Другие вопросы по теме