0

我有一个 Keycloak 领域,其中一些用户作为 nodejs + typescript 项目的 IdP。

我目前有这两个会议,如它所示: 照片

如果我按下全部注销,它们会从这里消失,但它们仍然有效。

例子:

1) I create a new session. I get its JWT token as a response
2) I do a GET req on one of the protected routes with the token attached. It works.
4) I logout all sessions by pressing the button in that photo
5) I do the same GET req on the same protected route. It still works.
 I expect it NOT to work, because I previously logged out all sessions.

这是我的密钥斗篷配置

import express, {Application} from 'express';
import { Keycloak as KeycloakType } from "keycloak-connect";

var session = require('express-session');
var Keycloak = require('keycloak-connect');

let _keycloak: KeycloakType;

var memoryStore = new session.MemoryStore();

let kcConfig = {
    clientId: 'restapi',
    bearerOnly: true,
    serverUrl: 'http://localhost:8080/auth',
    realm: 'supercatalog',
    realmPublicKey: 'deleted'
};

function getKeycloak() {
    if (_keycloak) {
        return _keycloak;
    } 
    console.log("Initializing Keycloak...");
    _keycloak = new Keycloak({ store: memoryStore }, kcConfig);
    return _keycloak;
}

export {getKeycloak, memoryStore};

我的受保护路线

router.get('/', keycloak.protect(), async (req:Request, res:Response):Promise<void> => {
    var bearerToken: string = await (await keycloak.getGrant(req, res)).toString() as string;
    var decoded: any = jwtDecode(bearerToken);
    console.log(decoded.resource_access.restapi.roles);
    res.send("hello");
});

我误解了令牌流程吗?

4

2 回答 2

3

一般来说,会话​​独立于 JWT。JWT 的优点(和缺点)是应用程序可以仅使用颁发者公钥对它们进行加密验证,这些公钥可以是预先分解的,也可以是动态查找和缓存的。JWT 是自编码访问令牌的一个示例,这意味着您可以验证它而无需不断回调中央身份验证/授权服务。这使得它们非常适合在分布式系统和零信任架构中进行身份验证,前提是您可以信任颁发者的公钥,您可以验证并信任提供的 JWT。

但这有一个缺点。JWT 包含一个到期时间,在此之前应用程序将其视为有效。正如已经提到的,JWT 的消费者(如 REST API)不需要与发布服务对话来验证它。

因此,在您的特定情况下,您的应用程序会看到 JWT,对其进行加密验证并验证它是否未过期并因此接受它。

使用 JWT 的系统的去中心化性质意味着通常不会撤销 JWT 本身。这是因为它需要维护一个撤销列表,并且您必须有一个中央服务来做到这一点。这并不是说这在技术上是不可能的,但这样做首先会失去使用 JWT 的许多好处。

由于会话是独立于 JWT 进行管理的,因此您可以使会话无效,而为其发出的 JWT 仍然有效。如果您需要一个有效的会话,那么您必须独立于基于 JWT 的身份验证来强制执行。

于 2022-02-28T10:11:07.487 回答
2

您所缺少的称为 OAuth 2.0 的令牌自省。正如 RobV 所提到的,JWT 可用于验证访问令牌,但另一方面,可以对服务器进行网络调用以验证它。

使用时keycloak-connect,这是在grant-manager的函数validateAccessToken中实现的。另一方面,keycloak.protect()请求处理程序的构建方式是,如果访问令牌无效,它会使用刷新令牌来发布一个新令牌(比较代码)。因此,尽管您被按下注销,但它会自动让您再次登录。

您可以使用另一个自定义处理程序来内省令牌(也在此处讨论):

const introspection = async function (req: any, res: any, next: any) {
    try {
        let grant = await keycloak.getGrant(req, res);
        let isValid = await keycloak.grantManager.validateAccessToken(grant.access_token!!);
        if (!isValid) {
            return keycloak.accessDenied(req, res);
        } else {
            return next();
        }
    } catch (e) {
        console.log(e);
        return keycloak.accessDenied(req, res);
    }
}

app.get('/protected/resource', keycloak.checkSso(), introspection, function (req, res, next) {
    console.log('I am in');
}

Keycloak 只允许在客户端保密时调用自省端点。

于 2022-02-28T14:18:53.303 回答