无法使用持有者令牌使用密钥罩进行身份验证

omtl5h9j  于 2022-09-21  发布在  其他
关注(0)|答案(1)|浏览(166)

我有一个项目,有一个Python/Django后端。它位于密钥斗篷之后,用于身份验证。一切正常,用户可以使用Keyloak登录。

我们有一个客户端需要从后端访问一些端点的用例。我们希望为客户端提供某种类型的API密钥,这样他们就可以使用Keyloak进行身份验证,并以编程方式到达后端端点。在进行了一些研究之后,我们想到了使用离线令牌。我们能够获得令牌,并正在尝试将访问令牌添加为承载令牌。问题是我们无法通过登录屏幕。

我们使用的是Keyloak 17.0.0。

以下是在Python中的工作流程:


# Get the token

data = {
    "client_id": <id>,
    "client_secret": <secret>,
    "username": "admin",
    "password": "foo",
    "grant_type": "password",
    "scope": "openid offline_access"
}

response = requests.post('http://keycloak:8080/realms/<realm>/protocol/openid-connect/token',  headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data)

# What is returned in the response

{
 "access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkWVQ3eWJOdWM3ODN5OU53d3VabmdTaHNSMV83T0xtQ2E5NW5HZHh5bXZvIn0.eyJleHAiOjE2NjI3NDU5NjgsImlhdCI6MTY2Mjc0NTY2OCwianRpIjoiZjcyZDBhYWUtOGFlMy00NjA1LTgzMWYtYzdiN2YzN2E2MzY1IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL2FyY2FuZS1maXJlIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjJmNzM5ZGQ1LTQxZmUtNDVmNy1hYzBjLTM2NTU4N2MyNTE3MyIsInR5cCI6IkJlYXJlciIsImF6cCI6Im5naW54Iiwic2Vzc2lvbl9zdGF0ZSI6IjVjMGIzNGM2LTc2YWItNDJlNy04ZjBjLTljODEzNzA4ZjcwZCIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1hcmNhbmUtZmlyZSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIG9mZmxpbmVfYWNjZXNzIGVtYWlsIiwic2lkIjoiNWMwYjM0YzYtNzZhYi00MmU3LThmMGMtOWM4MTM3MDhmNzBkIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiQ2hyaXMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImdpdmVuX25hbWUiOiJDaHJpcyJ9.J3oPEDWw_c-L6jMySSBF1uNV9mjl7d8AFwky8kN71qhTEJLDJFWKznIQ0sAMK8pGenbYOQFGDnAiL5E5BGh5g97jkv-PK1xSsvjKjIEAJuH15FGIeHB8RSth7ZYPcca-2kzRsqfs9ueeKbe1IAMlMcFdKgX3qJa3MPsLLYWVBI5QbxTf068sWxAoWNWCQzYfyTnsZKnnbGEHzMyHyTjKaFfCHj8Y2lTw1RXeEVdts2ck8OVg5B66NHxu4KHQqnS2t3EhhX-vsovctrZ-yyX_KXkv9uaZ8OUjbsPcAFr0Ta8vcK5ay-FyXfmcApwp6JptNBcL4M54OHcYAV3wmJS5Tg",
 "expires_in":300,
 "refresh_expires_in":0,
 "refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlMWI1ZjRmNC0xY2RiLTQwZmUtYWI0OS0yODFmNWExNzE1Y2YifQ.eyJpYXQiOjE2NjI3NDU2NjgsImp0aSI6IjRkMDUwMWQyLTEwYzktNDcwYS1iNmExLWNmZTE3MGUwMzc5YyIsImlzcyI6Imh0dHA6Ly9rZXljbG9hazo4MDgwL3JlYWxtcy9hcmNhbmUtZmlyZSIsImF1ZCI6Imh0dHA6Ly9rZXljbG9hazo4MDgwL3JlYWxtcy9hcmNhbmUtZmlyZSIsInN1YiI6IjJmNzM5ZGQ1LTQxZmUtNDVmNy1hYzBjLTM2NTU4N2MyNTE3MyIsInR5cCI6Ik9mZmxpbmUiLCJhenAiOiJuZ2lueCIsInNlc3Npb25fc3RhdGUiOiI1YzBiMzRjNi03NmFiLTQyZTctOGYwYy05YzgxMzcwOGY3MGQiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIG9mZmxpbmVfYWNjZXNzIGVtYWlsIiwic2lkIjoiNWMwYjM0YzYtNzZhYi00MmU3LThmMGMtOWM4MTM3MDhmNzBkIn0.DOu_zKq5WFI4PcTn5Qpe-VFwOj-aLtvc3q9SACs51Ew",
 "token_type":"Bearer",
 "id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkWVQ3eWJOdWM3ODN5OU53d3VabmdTaHNSMV83T0xtQ2E5NW5HZHh5bXZvIn0.eyJleHAiOjE2NjI3NDU5NjgsImlhdCI6MTY2Mjc0NTY2OCwiYXV0aF90aW1lIjowLCJqdGkiOiI0MDI5ZmI1ZC05ZDQwLTQ5NTQtYmNiMC02MmYzOTU2YjdmOTIiLCJpc3MiOiJodHRwOi8va2V5Y2xvYWs6ODA4MC9yZWFsbXMvYXJjYW5lLWZpcmUiLCJhdWQiOiJuZ2lueCIsInN1YiI6IjJmNzM5ZGQ1LTQxZmUtNDVmNy1hYzBjLTM2NTU4N2MyNTE3MyIsInR5cCI6IklEIiwiYXpwIjoibmdpbngiLCJzZXNzaW9uX3N0YXRlIjoiNWMwYjM0YzYtNzZhYi00MmU3LThmMGMtOWM4MTM3MDhmNzBkIiwiYXRfaGFzaCI6InNuVW11a3I1VUZWbTRyYVlxM1FxVlEiLCJhY3IiOiIxIiwic2lkIjoiNWMwYjM0YzYtNzZhYi00MmU3LThmMGMtOWM4MTM3MDhmNzBkIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiQ2hyaXMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImdpdmVuX25hbWUiOiJDaHJpcyJ9.AUGLQUiA8gyz_yEz5mShGdgVS9vQx_LbmJ6Xh9sEqTtIo9rDgflhKBlGK_b8V8KHir1NExtcuLAlSdMAwJWZ02IzMPNazkYEqxM_PMJh3nLXV6Q7Ph9a4BoPsN2xs6c9BxhlrXKgN1NChm38cKZHnBzw0ZlXcGTJfJdQvGjO8GGiXlZuzo9JioCByn-ZQvWtfepEHKZREx6rVcahSBM5PNG1i8GATRbAIxWpl88CRwv6r9OHXcvdjEEZo8Jl4yePumchyEo9NGMnf2Vk0Alp-cZv90AIO91uUAwo6a3P-iT-rJvk-tfJVed7XzxDqOaUA4ZMD9kCmZCyERolglV2QQ",
 "not-before-policy":0,
 "session_state":"5c0b34c6-76ab-42e7-8f0c-9c813708f70d",
 "scope":"openid profile offline_access email"
}

# Make request to the backend endpoint

response = requests.get('http://localhost/api/foo', headers={'Authorization': 'Bearer ' + response.json().get('access_token')})

在响应中返回的只是Keyloak登录页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" class="login-pf">

<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="robots" content="noindex, nofollow">

            <meta name="viewport" content="width=device-width,initial-scale=1"/>
    <title>Sign in to***</title>
...

我不知道为什么我们无法通过登录页面。我想,如果我们在标题中提供访问令牌,我们就可以通过登录页面访问后端端点。

以下是我们的一些相关文件:

Dev.confNginx配置

server {
  listen 80;
  server_name localhost;
  charset utf-8;
  client_max_body_size 10000m;
  resolver 127.0.0.11 valid=30s ipv6=off;
  resolver_timeout 10s;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  # login with keycloak
  access_by_lua_file /etc/nginx/lua/auth.lua;
...

Nginx配置中使用的auth.lualua文件

local opts = {
  redirect_uri_path = "/redirect_uri",
  accept_none_alg = true,
  discovery = "http://keycloak:8080/realms/<realm>/.well-known/openid-configuration",
  client_id = <id>,
  client_secret = <secret>,
  redirect_uri_scheme = "http",
  logout_path = "/logout",
  redirect_after_logout_uri = "http://keycloak:8080/realms/<realm>/protocol/openid-connect/logout",
  post_logout_redirect_uri = "http://localhost",
  redirect_after_logout_with_id_token_hint = false,
  revoke_tokens_on_logout = true,
  session_contents = {id_token=true,access_token=true,user=true}
}
-- call introspect for OAuth 2.0 Bearer Access Token validation
local res, err = require("resty.openidc").authenticate(opts)
if err then
  ngx.status = 403
  ngx.say(err)
  ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- decode and send the user roles for this session
local jwt = require "resty.jwt"
local jwt_obj = jwt:load_jwt(res.access_token)
local cjson = require "cjson"
ngx.log(ngx.DEBUG, "res.access_token.sub=", cjson.encode(jwt_obj))

ngx.req.set_header("ACCESS-TOKEN", cjson.encode(jwt_obj))

Our Keycloak settings

我们无法通过登录屏幕访问我们的后端终端。我们的环境里有什么东西吗?我想知道这是不是我们Lua档案里的逻辑。此外,有没有更好的方法让客户端访问我们的终端?

任何帮助都将不胜感激。

dxxyhpgq

dxxyhpgq1#

我能够解决这个问题。我不得不更改Lua文件中的代码。

以下是我将其更改为:

local opts = {
  redirect_uri_path = "/redirect_uri",
  accept_none_alg = true,
  discovery = "http://keycloak:8080/realms/<realm>/.well-known/openid-configuration",
  client_id = <id>,
  client_secret = <secret>,
  redirect_uri_scheme = "http",
  logout_path = "/logout",
  redirect_after_logout_uri = "http://keycloak:8080/realms/<realm>/protocol/openid-connect/logout",
  post_logout_redirect_uri = "http://localhost",
  redirect_after_logout_with_id_token_hint = false,
  revoke_tokens_on_logout = true,
  session_contents = {id_token=true,access_token=true,user=true}
}

local oidc = require("resty.openidc")
-- call bearer_jwt_verify for OAuth 2.0 JWT validation
local res, err, access_token = oidc.bearer_jwt_verify(opts)
if err or not res then
  -- call authenticate for OpenID Connect user authentication
  res, err = oidc.authenticate(opts)
  access_token = res.access_token
  if err then
    ngx.status = 403
    ngx.say(err)
    ngx.exit(ngx.HTTP_FORBIDDEN)
  end
end
-- decode and send the user roles for this session
local jwt = require "resty.jwt"
local jwt_obj = jwt:load_jwt(access_token)
local cjson = require "cjson"
ngx.log(ngx.DEBUG, "res.access_token.sub=", cjson.encode(jwt_obj))

ngx.req.set_header("ACCESS-TOKEN", cjson.encode(jwt_obj))

我使用bearer_jwt_verify检查承载令牌。如果没有设置,则恢复到以前使用authenticate进行身份验证。

相关问题