Keycloak 会话 - 当我从管理页面断开它们时,它们仍然有效
Keycloak sessions - when I disconnect them from the admin page, they still work
我有一个 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.
这是我的 keycloak-config
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");
});
我是不是误解了令牌流程?
一般来说,session 是独立于 JWT 的。 JWT 的优点(和缺点)是应用程序可以仅使用颁发者 public 密钥对它们进行加密验证,这些密钥可以是 pre-shared 或动态查找和缓存。 JWT 是 self-encoded access token 的一个示例,这意味着您可以验证它而无需不断回调中央 authentication/authorization 服务。这使得它们非常适合分布式系统和 zero-trust 架构中的身份验证,只要您可以信任发行者 public 密钥,您就可以验证和信任所提供的 JWT。
但是 有一个缺点。 JWT 包含一个到期时间,在此之前应用程序将认为它是有效的。正如已经提到的 JWT 消费者,如 REST API,不需要与发布服务对话来验证它。
因此,在您的特定情况下,您的应用程序会看到一个 JWT,对其进行密码验证并确认它没有过期并接受它。
使用 JWT 的系统的去中心化性质意味着通常不会自行撤销 JWT。这是因为它需要维护撤销列表,并且您必须有一个中央服务来执行此操作。这并不是说这在技术上是不可能的,但这样做首先会失去使用 JWT 的很多好处。
由于会话是独立于 JWT 进行管理的,因此您可以使会话无效,而为其颁发的 JWT 仍然有效。如果你需要一个有效的会话,那么你必须独立于基于 JWT 的身份验证来强制执行。
您缺少的是 OAuth 2.0 的 Token introspection。正如 RobV 所提到的,JWT 可用于验证访问令牌,但另一方面,可以对服务器进行网络调用以验证它。
使用keycloak-connect
时,在grant-manager的函数validateAccessToken中实现。另一方面,keycloak.protect()
request-handler 是构建方式,如果 access-token 无效,则使用 refresh-token 发出新的(比较 code).因此,尽管您被按下注销,它会自动让您再次登录。
您可以使用另一个自定义处理程序来检查令牌(也讨论了 ):
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 只允许在客户端保密时调用内省端点。
我有一个 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.
这是我的 keycloak-config
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");
});
我是不是误解了令牌流程?
一般来说,session 是独立于 JWT 的。 JWT 的优点(和缺点)是应用程序可以仅使用颁发者 public 密钥对它们进行加密验证,这些密钥可以是 pre-shared 或动态查找和缓存。 JWT 是 self-encoded access token 的一个示例,这意味着您可以验证它而无需不断回调中央 authentication/authorization 服务。这使得它们非常适合分布式系统和 zero-trust 架构中的身份验证,只要您可以信任发行者 public 密钥,您就可以验证和信任所提供的 JWT。
但是 有一个缺点。 JWT 包含一个到期时间,在此之前应用程序将认为它是有效的。正如已经提到的 JWT 消费者,如 REST API,不需要与发布服务对话来验证它。
因此,在您的特定情况下,您的应用程序会看到一个 JWT,对其进行密码验证并确认它没有过期并接受它。
使用 JWT 的系统的去中心化性质意味着通常不会自行撤销 JWT。这是因为它需要维护撤销列表,并且您必须有一个中央服务来执行此操作。这并不是说这在技术上是不可能的,但这样做首先会失去使用 JWT 的很多好处。
由于会话是独立于 JWT 进行管理的,因此您可以使会话无效,而为其颁发的 JWT 仍然有效。如果你需要一个有效的会话,那么你必须独立于基于 JWT 的身份验证来强制执行。
您缺少的是 OAuth 2.0 的 Token introspection。正如 RobV 所提到的,JWT 可用于验证访问令牌,但另一方面,可以对服务器进行网络调用以验证它。
使用keycloak-connect
时,在grant-manager的函数validateAccessToken中实现。另一方面,keycloak.protect()
request-handler 是构建方式,如果 access-token 无效,则使用 refresh-token 发出新的(比较 code).因此,尽管您被按下注销,它会自动让您再次登录。
您可以使用另一个自定义处理程序来检查令牌(也讨论了
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 只允许在客户端保密时调用内省端点。