如何从Django代码中从KeyClope注销

如何从Django代码中从KeyClope注销,django,realm,keycloak,logout,idp,Django,Realm,Keycloak,Logout,Idp,无法从Django应用程序代码内部从KeyClope IDP注销。所有的stackoverflow答案对我来说都不起作用(大多数是针对所涉及组件的旧版本),KeyClope文档也是如此 最近,我们已经为基于Django的网站实现了基于Key斗篷的感知。对auth来说很好。 该应用程序由docker构建,有三个容器:8000端口上的网站、8080端口上的Keyclope db(postgres图像)、Keyclope(jboss/Keyclope图像) 现在,我必须向它添加“注销”功能,这意味着从

无法从Django应用程序代码内部从KeyClope IDP注销。所有的stackoverflow答案对我来说都不起作用(大多数是针对所涉及组件的旧版本),KeyClope文档也是如此

最近,我们已经为基于Django的网站实现了基于Key斗篷的感知。对auth来说很好。 该应用程序由docker构建,有三个容器:8000端口上的网站、8080端口上的Keyclope db(postgres图像)、Keyclope(jboss/Keyclope图像)

现在,我必须向它添加“注销”功能,这意味着从我的Django代码中唱出keydove,并将用户重定向回keydove登录屏幕

我的设置:

Django 2.2
Python 3.5
keycloak 7
social-auth-app-django         3.1.0
social-auth-core               3.2.0
建议如下:

POST/{realm}/users/{id}/logout

具有用户id和领域名称

这只产生404,所以我切换到这个模式(喜欢stackoverflow): POST/auth/realms/acc/protocol/openid连接/注销

这将返回403和错误: “禁止(未设置CSRF cookie):/{realm name}/users/{user id}/logout/”

我设法解决了这个问题(见下面的更新)

url.py

urlpaterns = [
....
    url(r'logout/$', logout_view, name='logout'),
...
]
from django.http import HttpResponseRedirect
import requests
def logout_view(request):
    url = '%s<realm name>/users/<user id>/logout/' % settings.LOGOUT_REDIRECT_URL

    r = requests.post(url, data = {})
    #r.status_code at this point is 403

    #also tried another sugestion: 
    url = '%sauth/realms/%s/protocol/openid-connect/logout/' % (settings.LOGOUT_REDIRECT_URL, '<some realm name>')

    r = requests.post(url, data = {})
    #r.status_code at this point is 403

    #also tried with refresh_token and client_id:
    url = "http://<website ip>:8000/<realm name>/users/<user id>/logout/"
    refresh_token = '<some refresh token pulled out from stout>'
    r = requests.post(url, data = {'refresh_token': refresh_token, 'client_id': '<user id>'})
    #for 'client_id' above tried both user id and user name
    #r.status_code at this point is also 403

    return HttpResponseRedirect("http://<website ip>:8000")
视图.py

urlpaterns = [
....
    url(r'logout/$', logout_view, name='logout'),
...
]
from django.http import HttpResponseRedirect
import requests
def logout_view(request):
    url = '%s<realm name>/users/<user id>/logout/' % settings.LOGOUT_REDIRECT_URL

    r = requests.post(url, data = {})
    #r.status_code at this point is 403

    #also tried another sugestion: 
    url = '%sauth/realms/%s/protocol/openid-connect/logout/' % (settings.LOGOUT_REDIRECT_URL, '<some realm name>')

    r = requests.post(url, data = {})
    #r.status_code at this point is 403

    #also tried with refresh_token and client_id:
    url = "http://<website ip>:8000/<realm name>/users/<user id>/logout/"
    refresh_token = '<some refresh token pulled out from stout>'
    r = requests.post(url, data = {'refresh_token': refresh_token, 'client_id': '<user id>'})
    #for 'client_id' above tried both user id and user name
    #r.status_code at this point is also 403

    return HttpResponseRedirect("http://<website ip>:8000")
…但没有效果

那么,我在哪里可以找到一个使用Django代码的示例,该代码可以让用户从KeyClope注销?谢谢

更新 谜题的第一部分已经解决了(阅读,答案由和类似的帖子):为了摆脱“CSRF cookie not set”错误,我必须做一件简单的事情:

from django.views.decorators.csrf import csrf_exempt
并为我的注销视图添加装饰器:

@csrf_exempt
def logout_view(request):
   ..........
之后,执行注销请求,并返回以下内容:

[org.keycloak.events] (default task-12) type=LOGOUT_ERROR, realmId=acclims, clientId=63cb82ff-17f4-4f2d-95e1-a8b3c742e28b, userId=null, ipAddress=172.22.0.1, error=invalid_client_credentials

status_code: 400
我猜我没有发回正确的刷新令牌,我不知道如何测试这种怀疑

------------------------------------------------------- 其他部分(可能不相关):

设置.py

.....
LOGIN_URL = SCRIPT_NAME +  '/login/keycloak'

#yes, I tried this:
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_SECURE = False

SOCIAL_AUTH_KEYCLOAK_KEY = '<some keycloak key>'
SOCIAL_AUTH_KEYCLOAK_SECRET = 'some keycloak secret'
SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = 'some public key'
SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = 'http://<some ip>:8080/auth/realms/<some realm>/protocol/openid-connect/auth'
SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = 'http://<some ip>:8080/auth/realms/<some realm>/protocol/openid-connect/token'

SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy'
SOCIAL_AUTH_STORAGE = 'social_django.models.DjangoStorage'

SOCIAL_AUTH_KEYCLOAK_ID_KEY = 'email'
SOCIAL_AUTH_POSTGRES_JSONFIELD = True
SOCIAL_AUTH_URL_NAMESPACE = 'social'
LOGIN_REDIRECT_URL = 'http://<website ip>:8000/'
LOGOUT_REDIRECT_URL = 'http://<website ip>:8000/'

SOCIAL_AUTH_POSTGRES_JSONFIELD = True

SOCIAL_AUTH_PIPELINE = (
    'social_core.pipeline.social_auth.social_details',
    'social_core.pipeline.social_auth.social_uid',
    'social_core.pipeline.social_auth.auth_allowed',
    'social_core.pipeline.social_auth.social_user',
    'social_core.pipeline.user.get_username',
    'social_core.pipeline.mail.mail_validation',
    'social_core.pipeline.user.create_user',
    'social_core.pipeline.social_auth.associate_user',
    'social_core.pipeline.debug.debug',
    'social_core.pipeline.social_auth.load_extra_data',
    'social_core.pipeline.user.user_details',
    'social_core.pipeline.debug.debug',
)
....
。。。。。
LOGIN\u URL=SCRIPT\u NAME+'/LOGIN/keydave'
#是的,我试过这个:
CSRF\u COOKIE\u SECURE=False
会话\u COOKIE\u SECURE=False
社交身份验证密钥伪装密钥=“”
SOCIAL_AUTH_keydove_SECRET='some keydove SECRET'
社交密钥(AUTH)密钥(keydape)(PUBLIC)="某些公钥"
社交身份验证密钥伪装授权URL='http://:8080/AUTH/realms//protocol/openid connect/AUTH'
社交身份验证密钥伪装访问令牌URL='http://:8080/AUTH/realms//protocol/openid connect/TOKEN'
SOCIAL_AUTH_STRATEGY='SOCIAL_django.STRATEGY.DjangoStrategy'
SOCIAL_AUTH_STORAGE='SOCIAL_django.models.DjangoStorage'
社交身份验证密钥伪装ID密钥='email'
社交网站(AUTH\u POSTGRES\u JSONFIELD)=True
社交\u身份验证\u URL\u命名空间='SOCIAL'
登录\重定向\ URL='http://:8000/'
注销\u重定向\u URL='http://:8000/'
社交网站(AUTH\u POSTGRES\u JSONFIELD)=True
社会认证管道=(
“社交核心.管道.社交授权.社交详细信息”,
“social_core.pipeline.social_auth.social_uid”,
“允许社交核心.管道.社交身份验证.身份验证”,
“social_core.pipeline.social_auth.social_user”,
“social_core.pipeline.user.get_username”,
“social_core.pipeline.mail.mail_验证”,
“social_core.pipeline.user.create_user”,
“社交核心.pipeline.socialauth.associate用户”,
“social_core.pipeline.debug.debug”,
“社交核心.管道.社交身份验证.加载额外数据”,
“social_core.pipeline.user.user_details”,
“social_core.pipeline.debug.debug”,
)
....
docker compose.yml

version: '3'

services:
  web:
    restart: unless-stopped
    container_name: web-container
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "8000:8000"
    environment:
      PRODUCTION: 'false'
      DEBUG: 'True'
      DJANGO_SETTINGS_MODULE: '<something>.settings.postgres'
      DB_NAME: '<some name>'
      DB_USER: '<some user>'
      DB_PASS: '<some password>'
      DB_HOST: '<some host>'
    depends_on: 
      - db
    volumes:
      - ./:/usr/src/app/

  db:
    image: postgres:9.6.2
    # volumes:
    #     - ../docker-postgresql-multiple-databases:/docker-entrypoint-initdb.d
    volumes:
      - data:/var/lib/postgresql/data
    environment:
      - POSTGRES_MULTIPLE_DATABASES=<something>
      - POSTGRES_USER=<some user>
      - POSTGRES_PASSWORD=<some password>

  keycloakdb:
      image: postgres
      volumes:
        - keycloak_postgres_data:/var/lib/postgresql/data
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password

  keycloak:
      image: jboss/keycloak
      command: -b 0.0.0.0 -Dkeycloak.migration.action=import -Dkeycloak.migration.provider=dir -Dkeycloak.migration.dir=/tmp/
      environment:
        DB_VENDOR: POSTGRES
        DB_ADDR: keycloakdb
        DB_DATABASE: keycloak
        DB_USER: keycloak
        DB_SCHEMA: public
        DB_PASSWORD: <some password>
        KEYCLOAK_USER: <some user>
        KEYCLOAK_PASSWORD: <some password>
        #KEYCLOAK_IMPORT: /tmp/
      ports:
        - 8080:8080
      volumes:
        - ./keycloak/:/tmp/
      depends_on:
        - keycloakdb


volumes:
  data:
    # external: true
  keycloak_postgres_data:
      driver: local
版本:“3”
服务:
网状物:
重新启动:除非停止
容器名称:web容器
建造:
上下文:。
dockerfile:dockerfile.dev
端口:
- "8000:8000"
环境:
制作:'假'
调试:“True”
DJANGO_设置_模块:'.SETTINGS.postgres'
数据库名称:“”
DB\u用户:“”
DB_通行证:“”
DB\u主机:“”
取决于:
-分贝
卷数:
-./:/usr/src/app/
db:
图片:postgres:9.6.2
#卷数:
#-../docker postgresql多数据库:/docker entrypoint initdb.d
卷数:
-数据:/var/lib/postgresql/data
环境:
-POSTGRES\u多个\u数据库=
-POSTGRES_用户=
-POSTGRES_密码=
keydb:
图片:博士后
卷数:
-keydape\u postgres\u data:/var/lib/postgresql/data
环境:
博士后:钥匙斗篷
POSTGRES_用户:密钥斗篷
POSTGRES_密码:PASSWORD
钥匙斗篷:
图片:jboss/keydape
命令:-b 0.0.0.0-dkeydepose.migration.action=import-dkeydepose.migration.provider=dir-dkeydepose.migration.dir=/tmp/
环境:
DB_供应商:POSTGRES
数据库地址:keydavepdb
DB_数据库:密钥斗篷
DB_用户:密钥斗篷
DB_模式:公共
DB_密码:
密钥斗篷用户:
密钥隐藏密码:
#keydove\u导入:/tmp/
端口:
- 8080:8080
卷数:
-./keydove/:/tmp/
取决于:
-密钥隐藏数据库
卷数:
数据:
#外部:正确
密钥斗篷\u postgres\u数据:
司机:本地
keydape/realm.json

{
  "id" : "<some realm id>",
  "realm" : "<some realm name>",
  "notBefore" : 0,
  "revokeRefreshToken" : false,
  "refreshTokenMaxReuse" : 0,
  "accessTokenLifespan" : 300,
  "accessTokenLifespanForImplicitFlow" : 900,
  "ssoSessionIdleTimeout" : 1800,
  "ssoSessionMaxLifespan" : 36000,
  "ssoSessionIdleTimeoutRememberMe" : 0,
  "ssoSessionMaxLifespanRememberMe" : 0,
  "offlineSessionIdleTimeout" : 2592000,
  "offlineSessionMaxLifespanEnabled" : false,
  "offlineSessionMaxLifespan" : 5184000,
  "accessCodeLifespan" : 60,
  "accessCodeLifespanUserAction" : 300,
  "accessCodeLifespanLogin" : 1800,
  "actionTokenGeneratedByAdminLifespan" : 43200,
  "actionTokenGeneratedByUserLifespan" : 300,
  "enabled" : true,
  "sslRequired" : "external",
  "registrationAllowed" : false,
  "registrationEmailAsUsername" : false,
  "rememberMe" : false,
  "verifyEmail" : false,
  "loginWithEmailAllowed" : true,
  "duplicateEmailsAllowed" : false,
  "resetPasswordAllowed" : false,
  "editUsernameAllowed" : false,
  "bruteForceProtected" : false,
  "permanentLockout" : false,
  "maxFailureWaitSeconds" : 900,
  "minimumQuickLoginWaitSeconds" : 60,
  "waitIncrementSeconds" : 60,
  "quickLoginCheckMilliSeconds" : 1000,
  "maxDeltaTimeSeconds" : 43200,
  "failureFactor" : 30,
  "roles" : {
    ....bunch of roles
}
{
“id”:“,
“领域”:“,
“notBefore”:0,
“revokeRefreshToken”:false,
“refreshTokenMaxReuse”:0,
“寿命”:300,
“accessTokenLifespanForImplicitFlow”:900,
“ssoSessionIdleTimeout”:1800,
“ssoSessionMaxLifespan”:36000,
“SSOSessionDLeTimeoutMemberme”:0,
“SSOSessionMaxLifeSpanMemberme”:0,
“offlineSessionIdleTimeout”:2592000,
“offlineSessionMaxLifespanEnabled”:false,
“offlineSessionMaxLifespan”:5184000,
“使用寿命”:60,
“accessCodeLifespanUserAction”:300,
“accessCodeLifespanLogin”:1800,
“actionTokenGeneratedByAdminLifespan”:43200,
“actionTokenGeneratedByUserLifespan”:300,
“启用”:正确,
“sslRequired”:“外部”,
“RegistrationLowed”:错误,
“RegistrationMailAsUserName”:false,
“记住”:错,
“验证电子邮件”:false,
“loginWithEmailAllowed”:true,
“重复:错误,
“resetPasswordAllowed”:false,
“EditUserName允许