我已经试了好几个小时了,似乎遇到了麻烦.如有任何建议/帮助,将不胜感激.

Goal:我想授权express rest api(ex client id:"我的rest api")跨映射到客户端范围的各种HTTP方法路由(示例资源:"WeatherForecast")(示例:"创建"/"读取"/"更新"/"删除").我想通过策略来控制这些权限(例如,如果满足策略"仅管理组"(用户属于管理组),将授予"Read-WeatherForecast-Permission".

Rest api不会让用户登录(将从前端直接与KeyClope对话,然后他们将使用该令牌与Rest api对话).

Environment:

What Happens:我可以通过postman 从Keyclope登录页面登录,并获得访问令牌.然而,当我点击任何使用KeyClope的端点时.保护()或 keys 斗篷.enforce()(有或没有指定资源权限)我无法通过.在下面的代码中,delete端点返回200+postman中KeyClope登录页面的HTML,Get返回403+"拒绝访问".

Current State of Realm

  • 测试用户(我在Postman中与他一起登录)拥有组"Admin".
  • 客户端"我的rest api",访问类型:机密,启用授权.
  • 授权设置:

Current State of Nodejs Code:

import express from 'express';
import bodyParser from 'body-parser';
import session from "express-session";
import KeycloakConnect from 'keycloak-connect';

const app = express();

app.use(bodyParser.json());

const memoryStore = new session.MemoryStore();
app.use(session({
    secret: 'some secret',
    resave: false,
    saveUninitialized: true,
    store: memoryStore
  }));

const kcConfig: any = { 
    clientId: 'my-rest-api',
    bearerOnly: true,
    serverUrl: 'http://localhost:8080/auth',
    realm: 'my-realm',
};
const keycloak = new KeycloakConnect({ store: memoryStore }, kcConfig);

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

app.get('/api/WeatherForecast', keycloak.enforcer(['WeatherForecast:read'],{  resource_server_id: "my-rest-api"}), function (req, res) {
   res.json("GET worked")
  });

app.delete('/api/WeatherForecast', keycloak.protect(), function (req, res) {
     res.json("DELETE worked")
});

app.listen(8081, () => {
    console.log(`server running on port 8081`);
  });
  

A Few Other Things Tried:

  • 我试着用从postman 那里得到的令牌用curl调用RPT端点,结果RPT令牌非常好,看到了预期的权限.
  • 我试着打电话给Keyclope.判断权限({permissions:[{id:"WeatherForecast",作用域:["read"]}]},请求).然后(grant=>res.json(grant.access_token));从一个不安全的端点内部获得"连接被拒绝127.0.0.1:8080".
  • 我试着禁用策略执行模式只是为了看看,仍然被拒绝访问/403.
  • 我试着用 keys 斗篷.json配置,而不是上面的对象方法——无论哪种方式,结果都是一样的.
  • 我try 了openid客户端(来自另一个教程),也遇到了一些问题.
  • 我试过使用docker主机ip,主机.docker .内部、容器名称等都没有用(尽管我不认为这是一个问题,因为我显然可以点击auth服务并获得第一个访问令牌).

我真的很想使用KeyClope,我觉得我的团队很快就能做到这一点,但需要一些帮助才能通过这一部分.非常感谢.

------------------- END ORIGINAL QUESTION ------------------------

EDIT/UPDATE #1:

'{"protocol":"http:","slashes":true,"auth":null,"host":"localhost:8080","port":"8080","hostname":"localhost","hash":null,"search":null,"query":null,"pathname":"/auth/realms/my-realm/protocol/openid-connect/token","path":"/auth/realms/my-realm/protocol/openid-connect/token","href":"http://localhost:8080/auth/realms/my-realm/protocol/openid-connect/token","headers":{"Content-Type":"application/x-www-form-urlencoded","X-Client":"keycloak-nodejs-connect","Authorization":"Basic YW(etc...)Z2dP","Content-Length":1498},"method":"POST"}'

它似乎没有进入fetch/http包装器的回调.我将NODE_DEBUG=http添加到我的启动命令中,并且能够找到被吞没的错误,看起来我回到了起点:

HTTP 31: SOCKET ERROR: connect ECONNREFUSED 127.0.0.1:8080 Error: connect ECONNREFUSED 127.0.0.1:8080

    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1157:16)

    at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17)

然后,我看到了一些我认为可能与docker网络设置(Keycloak and Spring Boot web app in dockerized environment)有关的东西,并try 更改主机名dns,以便使用本地主机以外的其他主机,但也不起作用(甚至添加到重定向uri等).

UPDATE #2:

const kcConfig: any = { 
    clientId: 'my-rest-api',
    bearerOnly: true,
    serverUrl: 'http://localhost:8080/auth',
    realm: 'my-realm',
    realmPublicKey : "MIIBIjANBgk (...etc) uQIDAQAB",
};

推荐答案

所以我的团队最终找到了答案——解决方案分为两部分:

  1. 按照类似问题的说明回答问题,例如:https://stackoverflow.com/a/51878212/5117487
  • 为127.0.0.1 keydrope添加hosts条目(如果"keydrope"是keydrope的docker容器的名称,我将docker compose更改为指定容器名称,使其更简单)
  • 将KeyClope connect配置authServerUrl设置更改为:'http://keycloak:8080/auth/"而不是"http://localhost:8080/auth/'
  1. Postman OAuth 2.0令牌请求验证URL和访问令牌URL更改为使用现在更新的主机条目:
  • "http://localhost:8080/auth/realms/abra/protocol/openid-连接/验证"->;"http://keycloak:8080/auth/realms/abra/protocol/openid-"连接/验证"
  • "http://localhost:8080/auth/realms/abra/protocol/openid-连接/令牌"->;

Node.js相关问答推荐

如何解决TypeError:requ.isAuthenticated不是函数错误?

容器端口是容器内 node 应用程序的端口吗?

Mongoose更新许多不使用数组作为筛选器来更新记录

用于SLACK命令返回json而不是文本的AWS lambda函数

使用单个 MongoDB 查询更新多个元素

如何在MongoDB中删除嵌套对象数组中的属性?

如果我在父文件夹中运行,子进程生成不起作用

如何修改这个flake.nix,这样我就不用每次加载环境都加载nix包了

module.exports=require('other') 和临时变量有什么区别?

MongoDB Aggregate - 如何使用前一阶段的值作为下一阶段的字段名称?

如何找到特定文档并更新数组中特定键的值?

try 在 Heroku 中部署 PRN 应用程序并获得 404

MERN 堆栈项目中的 React [create-react-app] 正在提供依赖项

在 gatsby 中安装软件包时不推荐使用的错误

配额超出了每分钟的 Sheets API 写入请求数. node .js

Handlebars:访问已被拒绝解析来自的属性,因为它不是其父级的自己的属性

Puppeteer 错误:未下载 Chromium 修订版

有人在 NodeJS 中实现过 wiki 吗?

User.findOrCreate 函数是做什么的,什么时候在Passport 中调用它?

JavaScript 异步编程:promise 与生成器