Я пытаюсь получить информацию о пользователе из 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 маршрут всегда возвращает «Доступ запрещен». Что мне следует сделать в консоли администратора, чтобы решить эту проблему?
Я пробовал играть с ролями в консоли администратора, но это не помогло.
Докер @MocktarIssa
Вам необходимо включить и настроить службы авторизации в Keycloak. Это включает в себя настройку политик, разрешений, ресурсов и областей.
Resources
: вещи, которые вы хотите защитить, например API, веб-страницы или любой другой ресурс. Это цель API.
Scopes
: Это действие, например чтение, запись или удаление, выполняемое над ресурсом.
Permission
: связь между ресурсами и областью действия. Он решает разрешить или запретить доступ к ресурсу.
Policy
: Определите условия, при которых предоставляется доступ к ресурсу.
Я воспользуюсь keycloak-nodejs-connect
примером
Я покажу, что имя пользователя user
— это ошибка 403, но имя пользователя admin
не является ошибкой Access granted to Default Resource
.
user
admin
Есть много шагов, Пожалуйста, следуйте за мной шаг за шагом.
В здесь
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
.
admin
пароль 1234
Результат политики установки
Результат разрешения на установку
Дерево файлов
Сохранить как 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"
}
}
npm install
node index.js
http://localhost:3000
Полномочия
username: user
password: password
Результат
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 без пользовательского интерфейса (только серверная часть), процесс тот же?
а также не могли бы вы показать, как получить атрибуты пользователя после промежуточного программного обеспечения?
keycloak-nodejs-connect служит промежуточным программным обеспечением, использующим поток кода аутентификации, который предназначен для сценариев, когда пользователь входит в систему через пользовательский интерфейс. Процесс не тот. Я рекомендую использовать вызов REST API из бэкэнда вместо использования keycloak-nodejs-connect
. Вы можете получить атрибуты пользователя путем декодирования токена в здесь
Где вы используете keycloak. На удаленном экземпляре? В Docker или через бинарный файл?