Keycloak:访问令牌验证端点
Keycloak: Access token validation end point
运行 独立 mode.and 上的 keycloak 通过使用 node.js 适配器来验证 api 调用创建了一个微服务。
来自 keyclaok 的 jwt 令牌随每个 api 调用一起发送。它只会在发送的令牌有效时响应。
- 如何验证来自微服务的访问令牌?
- keycloak 是否提供任何令牌验证?
我会为此使用这个 UserInfo 端点,您还可以使用它检查其他属性,例如电子邮件以及您在映射器中定义的内容。您必须使用 Bearer 在 header 属性中发送访问令牌
授权:不记名 access_token
http://localhost:8081/auth/realms/demo/protocol/openid-connect/userinfo
展开:
Question 1: How can I validate the access token from the micro service?
实现一个函数来检查每个持有者令牌请求,并在将令牌传递给 api 的路由处理程序之前发送该令牌以供您的 keycloak 服务器在 userinfo 端点进行验证。
您可以通过请求 .
找到您的 keycloak 服务器的特定端点(如 userinfo 路由)
如果您在您的节点中使用 expressjs api,这可能如下所示:
const express = require("express");
const request = require("request");
const app = express();
/*
* additional express app config
* app.use(bodyParser.json());
* app.use(bodyParser.urlencoded({ extended: false }));
*/
const keycloakHost = 'your keycloak host';
const keycloakPort = 'your keycloak port';
const realmName = 'your keycloak realm';
// check each request for a valid bearer token
app.use((req, res, next) => {
// assumes bearer token is passed as an authorization header
if (req.headers.authorization) {
// configure the request to your keycloak server
const options = {
method: 'GET',
url: `https://${keycloakHost}:${keycloakPort}/auth/realms/${realmName}/protocol/openid-connect/userinfo`,
headers: {
// add the token you received to the userinfo request, sent to keycloak
Authorization: req.headers.authorization,
},
};
// send a request to the userinfo endpoint on keycloak
request(options, (error, response, body) => {
if (error) throw new Error(error);
// if the request status isn't "OK", the token is invalid
if (response.statusCode !== 200) {
res.status(401).json({
error: `unauthorized`,
});
}
// the token is valid pass request onto your next function
else {
next();
}
});
} else {
// there is no token, don't process request further
res.status(401).json({
error: `unauthorized`,
});
});
// configure your other routes
app.use('/some-route', (req, res) => {
/*
* api route logic
*/
});
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
Question 2: Is there any token validation availed by Keycloak?
向 Keycloak 的 userinfo 端点发出请求是验证您的令牌是否有效的一种简单方法。
来自有效令牌的用户信息响应:
Status: 200 OK
{
"sub": "xxx-xxx-xxx-xxx-xxx",
"name": "John Smith",
"preferred_username": "jsmith",
"given_name": "John",
"family_name": "Smith",
"email": "john.smith@example.com"
}
来自无效有效令牌的用户信息响应:
Status: 401 Unauthorized
{
"error": "invalid_token",
"error_description": "Token invalid: Token is not active"
}
附加信息:
Keycloak 提供了自己的 npm 包,名为 keycloak-connect。该文档描述了路由上的简单身份验证,要求用户登录才能访问资源:
app.get( '/complain', keycloak.protect(), complaintHandler );
我还没有发现这种方法可以使用仅承载身份验证。根据我的经验,在路由上实施这种简单的身份验证方法会导致 "access denied" 响应。 also asks about how to authenticate a rest api using a Keycloak access token. 建议也使用 keycloak-connect 提供的简单身份验证方法,但正如 Alex 在评论中所述:
"The keyloak.protect() function (doesn't) get the bearer token from
the header. I'm still searching for this solution to do bearer only
authentication – alex Nov 2 '17 at 14:02
有两种验证令牌的方法:
- 在线
- 离线
上述变体是在线验证。这当然是非常昂贵的,因为它为每次验证引入了另一个 http/round 行程。
离线效率更高验证:JWT令牌是base64编码的JSON对象,已经包含所有信息(声明)进行离线验证。您只需要 public 密钥并验证签名(以确保内容是 "valid"):
有几个库(例如 keycloak-backend)可以离线进行验证,无需任何远程请求。离线验证就这么简单:
token = await keycloak.jwt.verifyOffline(someAccessToken, cert);
console.log(token); //prints the complete contents, with all the user/token/claim information...
为什么不使用官方 keycloak-connect
node.js 库(而是使用 keycloak-backend)?官方库更侧重于将 express 框架作为中间件,并且(据我所知)不直接公开任何验证功能。或者您可以使用任意 JWT/OICD 库,因为验证是一个标准化过程。
@kfrisbie 感谢您的回复,根据您的示例,我可以使用 keycloak 连接适配器重构您的代码:
// app.js
app.use(keycloakConfig.validateTokenKeycloak); // valid token with keycloak server
// add routes
const MyProtectedRoute = require('./routes/protected-routes'); // routes using keycloak.protect('some-role')
app.use('/protected', MyProtectedRoute);
因此,当发送授权 header 时,我可以验证令牌对 keycloak 服务器仍然有效,因此如果在令牌过期之前从管理控制台或前端 spa 注销,我的休息 api抛出401错误,其他情况使用keycloak protect方法。
// keycloak.config.js
let memoryStore = new session.MemoryStore();
let _keycloak = new Keycloak({ store: memoryStore });
async function validateTokenKeycloak(req, res, next) {
if (req.kauth && req.kauth.grant) {
console.log('--- Verify token ---');
try {
var result = await _keycloak.grantManager.userInfo(req.kauth.grant.access_token);
//var result = await _keycloak.grantManager.validateAccessToken(req.kauth.grant.access_token);
if(!result) {
console.log(`result:`, result);
throw Error('Invalid Token');
}
} catch (error) {
console.log(`Error: ${error.message}`);
return next(createError.Unauthorized());
}
}
next();
}
module.exports = {
validateTokenKeycloak
};
运行 独立 mode.and 上的 keycloak 通过使用 node.js 适配器来验证 api 调用创建了一个微服务。
来自 keyclaok 的jwt 令牌随每个 api 调用一起发送。它只会在发送的令牌有效时响应。
- 如何验证来自微服务的访问令牌?
- keycloak 是否提供任何令牌验证?
我会为此使用这个 UserInfo 端点,您还可以使用它检查其他属性,例如电子邮件以及您在映射器中定义的内容。您必须使用 Bearer 在 header 属性中发送访问令牌 授权:不记名 access_token
http://localhost:8081/auth/realms/demo/protocol/openid-connect/userinfo
展开
Question 1: How can I validate the access token from the micro service?
实现一个函数来检查每个持有者令牌请求,并在将令牌传递给 api 的路由处理程序之前发送该令牌以供您的 keycloak 服务器在 userinfo 端点进行验证。
您可以通过请求
如果您在您的节点中使用 expressjs api,这可能如下所示:
const express = require("express");
const request = require("request");
const app = express();
/*
* additional express app config
* app.use(bodyParser.json());
* app.use(bodyParser.urlencoded({ extended: false }));
*/
const keycloakHost = 'your keycloak host';
const keycloakPort = 'your keycloak port';
const realmName = 'your keycloak realm';
// check each request for a valid bearer token
app.use((req, res, next) => {
// assumes bearer token is passed as an authorization header
if (req.headers.authorization) {
// configure the request to your keycloak server
const options = {
method: 'GET',
url: `https://${keycloakHost}:${keycloakPort}/auth/realms/${realmName}/protocol/openid-connect/userinfo`,
headers: {
// add the token you received to the userinfo request, sent to keycloak
Authorization: req.headers.authorization,
},
};
// send a request to the userinfo endpoint on keycloak
request(options, (error, response, body) => {
if (error) throw new Error(error);
// if the request status isn't "OK", the token is invalid
if (response.statusCode !== 200) {
res.status(401).json({
error: `unauthorized`,
});
}
// the token is valid pass request onto your next function
else {
next();
}
});
} else {
// there is no token, don't process request further
res.status(401).json({
error: `unauthorized`,
});
});
// configure your other routes
app.use('/some-route', (req, res) => {
/*
* api route logic
*/
});
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
Question 2: Is there any token validation availed by Keycloak?
向 Keycloak 的 userinfo 端点发出请求是验证您的令牌是否有效的一种简单方法。
来自有效令牌的用户信息响应:
Status: 200 OK
{
"sub": "xxx-xxx-xxx-xxx-xxx",
"name": "John Smith",
"preferred_username": "jsmith",
"given_name": "John",
"family_name": "Smith",
"email": "john.smith@example.com"
}
来自无效有效令牌的用户信息响应:
Status: 401 Unauthorized
{
"error": "invalid_token",
"error_description": "Token invalid: Token is not active"
}
附加信息:
Keycloak 提供了自己的 npm 包,名为 keycloak-connect。该文档描述了路由上的简单身份验证,要求用户登录才能访问资源:
app.get( '/complain', keycloak.protect(), complaintHandler );
我还没有发现这种方法可以使用仅承载身份验证。根据我的经验,在路由上实施这种简单的身份验证方法会导致 "access denied" 响应。
"The keyloak.protect() function (doesn't) get the bearer token from the header. I'm still searching for this solution to do bearer only authentication – alex Nov 2 '17 at 14:02
有两种验证令牌的方法:
- 在线
- 离线
上述变体是在线验证。这当然是非常昂贵的,因为它为每次验证引入了另一个 http/round 行程。
离线效率更高验证:JWT令牌是base64编码的JSON对象,已经包含所有信息(声明)进行离线验证。您只需要 public 密钥并验证签名(以确保内容是 "valid"):
有几个库(例如 keycloak-backend)可以离线进行验证,无需任何远程请求。离线验证就这么简单:
token = await keycloak.jwt.verifyOffline(someAccessToken, cert);
console.log(token); //prints the complete contents, with all the user/token/claim information...
为什么不使用官方 keycloak-connect
node.js 库(而是使用 keycloak-backend)?官方库更侧重于将 express 框架作为中间件,并且(据我所知)不直接公开任何验证功能。或者您可以使用任意 JWT/OICD 库,因为验证是一个标准化过程。
@kfrisbie 感谢您的回复,根据您的示例,我可以使用 keycloak 连接适配器重构您的代码:
// app.js
app.use(keycloakConfig.validateTokenKeycloak); // valid token with keycloak server
// add routes
const MyProtectedRoute = require('./routes/protected-routes'); // routes using keycloak.protect('some-role')
app.use('/protected', MyProtectedRoute);
因此,当发送授权 header 时,我可以验证令牌对 keycloak 服务器仍然有效,因此如果在令牌过期之前从管理控制台或前端 spa 注销,我的休息 api抛出401错误,其他情况使用keycloak protect方法。
// keycloak.config.js
let memoryStore = new session.MemoryStore();
let _keycloak = new Keycloak({ store: memoryStore });
async function validateTokenKeycloak(req, res, next) {
if (req.kauth && req.kauth.grant) {
console.log('--- Verify token ---');
try {
var result = await _keycloak.grantManager.userInfo(req.kauth.grant.access_token);
//var result = await _keycloak.grantManager.validateAccessToken(req.kauth.grant.access_token);
if(!result) {
console.log(`result:`, result);
throw Error('Invalid Token');
}
} catch (error) {
console.log(`Error: ${error.message}`);
return next(createError.Unauthorized());
}
}
next();
}
module.exports = {
validateTokenKeycloak
};