django 接入OIDC认证登录(django admin后台使用OIDC 或github账号登录) django 使用python-social-auth模块接入oidc 账号登录 ,django views视图接入接入oidc登录,django views通过oidc鉴权

参考文档

模块文档:https://python-social-auth.readthedocs.io/en/latest/

接入github账号登录参考: https://blog.csdn.net/yannanxiu/article/details/112622781; 测试项目地址:https://github.com/AngelLiang/django-social-auth-demo/tree/main

-- 创建github OAuth应用 : https://docs.github.com/zh/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app

 

 

关键词

django 、django admin、views、python-social-auth、social-auth-app-django、simpleui、登录失败、登录不成功、跳回登录页面、nginx + django + simpleui + social-auth-app-django

一、需求

1. django admin 后台登录用户通过oidc或者github登其他账号登录。

2.  django view 视图接入oidc登录,验证用户登录后才可访问。

 

二、采用模块

https://python-social-auth.readthedocs.io/en/latest/

1. 通过接入github账号登录

1.1 准备工作-获取github OAuth 应用 client id 和secret

在github 开发者平台新建一个 OAuth 应用。并填写下面信息:

Application name: django-social-auth-demo(可以随意填写)
Homepage URL: http://127.0.0.1:8000/admin/
Authorization callback URL: http://127.0.0.1:8000/complete/github/(固定,不能随便改动)

github 申请目录路径:Settings/Developer Settings/OAuth Apps

 

 

 按需填写应用名称、homepage、callbackurl

  • Application name: django-social-auth-demo(可以随意填写)
  • Homepage URL: http://127.0.0.1:8000/admin/
  • Authorization callback URL: http://127.0.0.1:8000/complete/github/(固定,不能随便改动)

 

 示例:我这里创建完成的如下

 1.2 安装django 插件 social-auth-app-django

pip  install  social-auth-app-django -i https://mirrors.aliyun.com/pypi/simple/
# 还有个插件python-social-auth忘记确认是依赖自动装的还是手动装的了,手动多装个也无所谓
# pip  install python-social-auth -i https://mirrors.aliyun.com/pypi/simple/

1.3 在django 项目 settings.py配置文件中进行配置

vim <项目目录><项目同名子目录>/settings.py

1.3.1添加social_django App

# vim <项目目录><项目同名子目录>/settings.py

INSTALLED_APPS = [
    ...
    # 1、添加 social_django app
    'social_django',
]

1.3.2 migrate 生成模块所需关联表 

在 项目根目录 执行 python manage.py migrate social_django

1.3.3 添加模板选项

# vim <项目目录><项目同名子目录>/settings.py
TEMPLATES = [
    {
        ...
        'OPTIONS': {
            'context_processors': [
                ...

                # 2、添加下面两句
                'social_django.context_processors.backends',
                'social_django.context_processors.login_redirect',
            ],
        },
    },
]

1.3.3 添加第三方登录验证方式

# vim <项目目录><项目同名子目录>/settings.py
# 3、自定义用户验证,添加第三方登录方式
AUTHENTICATION_BACKENDS = (
    # https://python-social-auth.readthedocs.io/en/latest/backends/github.html
    'social_core.backends.github.GithubOAuth2',    # Gtihub
    'django.contrib.auth.backends.ModelBackend',    # django默认的必须添加
)

1.3.4 配置github请求第三方验证用的client id 和secret

   这个就是准备工作中的获取的 

# vim <项目目录><项目同名子目录>/settings.py
# 4. 配置第三方平台对应的密匙
SOCIAL_AUTH_GITHUB_KEY = os.getenv('SOCIAL_AUTH_GITHUB_KEY', 'OxxxxxxxxxxOJ')
SOCIAL_AUTH_GITHUB_SECRET = os.getenv('SOCIAL_AUTH_GITHUB_SECRET', 'fbyyyyyyyyyyyyyyyyyyyyyyyyyc4')

即:

SOCIAL_AUTH_GITHUB_KEY 对应 Client ID
SOCIAL_AUTH_GITHUB_SECRET 对应 Client secrets

 

1.3.5 配置登录成功后重定向页面

# vim <项目目录><项目同名子目录>/settings.py
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/admin/'

1.3.6 其他非必须配置

# vim <项目目录><项目同名子目录>/settings.py
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True # 如果您想使用完整的电子邮件地址作为username,请定义此设置。
# SOCIAL_AUTH_CLEAN_USERNAMES = False  # 默认情况下,一组正则表达式会应用于用户名,以清除常见的不需要的字符(如空格)。将此设置设为False可禁用此行为。
SOCIAL_AUTH_LINKEDIN_OIDC_SCOPE = ['profile', 'openid', 'email', 'offline_access', 'name']

详见 https://python-social-auth.readthedocs.io/en/latest/configuration/settings.html

1.4 配置处理github回调的url

# vim <项目目录><项目同名子目录>/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    # 1.4 添加URL
    path('', include('social_django.urls', namespace='social')),
]

注:

  此url  social_django 将会自动注入两个URI

  • 1. 处理生成向第三方发起认证登录的URI:/login/github/, 这里的/github 是个变量,1.3.3步骤 里面AUTHENTICATION_BACKENDS添加了哪些第三方,/login/<第三方>/ 这个第三方就支持哪些。
  • 2. 第三方认证通过后处理第三方认证回调的URI:/complete/github/,同上这里的/github 也是个变量。

1.5 重写django.contrib.admin 的登录页面 【推荐1.5.2的方式】

 1.5.1 方式一、参考https://blog.csdn.net/yannanxiu/article/details/112622781

1.5.1.1  将django admin 模块内模板里的log.html 拷贝出来,放到项目目录templates目录下新建admin子目录,将login.html 放到子目录并修改增加github登录外链;

- 如何找模块目录?:在开发工具pycharm里点击模块位置即可在左边目录树内展示所在目录。

附 1.5.1.1 代码

增加请求用github登录的外链,使用模板语法{% url "social:begin" "github" %}

login.html copy 到项目根目录/templates/admin/过来后; 

 login.html form表单最下面增加: <a href="{% url "social:begin" "github" %}">GitHub+</a> ;

实际这里最好把整个admin目录copy过来。

vim  <django项目目录>/templates/admin/login.html 
{% extends "admin/base_site.html" %}
{% load i18n static %}
{# .... 等等其他原始内容不在赘复制#}
  <div class="submit-row">
    <input type="submit" value="{% translate 'Log in' %}">
  </div>
    <a href="{% url "social:begin" "github" %}">GitHub+</a>
</form>
</div>
{% endblock %}

此处语法在模块指导文档中也有,只不过用的认证第三方是谷歌:google-oauth2,需要替换成github:

https://python-social-auth.readthedocs.io/en/latest/configuration/django.html#templates

1.5.1.2  在自己已创建项目应用(python manage.py startapp xxx生成的)的应用目录admin.py中新建重写admin登录页面的站点l类 class MyAdminSite;

python manage.py startapp myadmin 
vim django项目目录/myadmin/admin.py
from django.contrib import admin

# Register your models here.

class MyAdminSite(admin.AdminSite):
    # 重写登录页面
    login_template = 'admin/login.html'


# 本文件是Django项目目录/myadmin/admin.py

1.5.1.3  在在自己已创建项目应用的应用目录apps.py中用上一步MyAdminSite站点新建admin后台站点配置类class MyAdminConfig; 

 

vim Django项目目录/myadmin/apps.py

 

Django项目目录/myadmin/apps.py 内容

 

 

from django.apps import AppConfig
#
#
class MyadminConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myadmin'

# apps.py
from django.contrib.admin.apps import AdminConfig
#
#
class MyAdminConfig(AdminConfig):
    default_site = 'myadmin.admin.MyAdminSite'
    name = 'myadmin'

 

1.5.1.4 在settings.py  INSTALLED_APPS 中替换django.contrib.admin。

--- 比如我是此前python manage.py startapp myadmin 创建的myadmin 这个app: 这里则用'myadmin.apps.MyAdminConfig' 替换'django.contrib.admin'

1.5.1.5 在django项目自定义的admin app应用myadmin包初始化文件__init__.py 下补充autodiscover()函数

vim Django项目目录/myadmin/__init__.py
Django项目目录/myadmin/__init__.py
from django.utils.module_loading import autodiscover_modules
from django.contrib.admin import site


def autodiscover():
    autodiscover_modules('myadmin', register_to=site)

为啥加它? 

答: 按照如上csdn链接测的时候报错没这个函数,故而到django.contrib.admin模块里翻了翻。发现django自己的admin有这个函数,复制治百病,我照抄过来了。此为最后整理各种坑的坑2

1.5.2 方式二、不需要替换settings里面的django.contrib.admin。(推荐)

实测效果:

效果原理:django项目目录/templates/ 下如果有admin/xxx.html 等admin界面目录,会自动优先从这里找文件,找不到才会去安装包目录里面读文件。

所需动作:

  • 直接将django.contrib.admin模块templates/admin 目录(或者用了simpleui的话把simpleui simples/admin), 目录复制到django项目目录/templates,修改admin的login.html;
  • 复制过来后,增加github+的外链,和错误提示代码块儿(如果是simpleui的admin template模板login.html文件)即可。

 

1.6 测试访问效果

访问admin后台

 点击github登录标签,github上授权后返回(此处遇到的坑2.最下面统一整理了)

 出现此无权限提示后,说明用户关联成功,在django中创立了github的同名用户。使用有权限的用户登录admin后台给自动创建的github同名用户加上权限,刷新浏览器即可完成登录。

 授权后刷新浏览器即可进入admin后台

 1.7 附:如果admin后台使用了simpleui,可以用simpleui 的amdin templates/admin 目录复制过来。

此处遇到坑3

 

2. 通过接入OIDC账号登录(延续上面配置)

 2.1 在AUTHENTICATION_BACKENDS 增加OIDC模块

vim settings.py

 'social_core.backends.open_id_connect.OpenIdConnectAuth'
# 3、自定义用户验证,添加第三方登录方式
AUTHENTICATION_BACKENDS = (
    # https://python-social-auth.readthedocs.io/en/latest/backends/github.html
    'social_core.backends.github.GithubOAuth2',    # Gtihub
    # 'social_core.backends.open_id.OpenIdAuth',      # OpenIdAuth
    'social_core.backends.open_id_connect.OpenIdConnectAuth',      # OpenIdConnectAuth 即OIDC 认证
    'django.contrib.auth.backends.ModelBackend',    # django默认的必须添加
)

2.2 增加OIDC 目的地址、key、Secret配置

vim settings.py

# 测试OIDC登录
# SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = 'https://oidc.xxxx.com/'  # 内网域名
SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = 'https://oidc-public.xxxx.com' # 公网域名
SOCIAL_AUTH_OIDC_KEY = 'key or client id'  # oidc认证提供者有的把这个叫做OIDC Name
SOCIAL_AUTH_OIDC_SECRET = 'xxxxzzzzzzyyyyy'  #  Secret 一般oidc认证提供这也叫Secret

2.3 在templates/admin/login.html中增加oidc登录外链

vim login.html

<a href="{% url "social:begin" "oidc" %}">用OIDC登录</a>

 效果

 效果

 3. django views视图启用oidc认证

1. 自制认证函数,认证函数中获取oidc认证通过的用户名。

如何获取认证用户?

request.user

我咋知道的?... 百度AI告诉我的。
PS: 没深入研究django,之前一直了解admin后台管理和前端视图鉴权逻辑分开的,现在看可以在视图中获取admin登录的用户。 我的场景够用了。

2. 装饰到需要鉴权的视图上。

vim xxxapp-name/views.py

# 1.自制认证函数,认证函数中获取oidc认证通过的用户名。
# 自己手写用户身份认证装饰器,未认证直接跳到登录页面,已认证就执行传进来的函数
def auth(func):
    def inner(request, *args, **kwargs):
        if request.user.is_authenticated:
            # 用户已经登录,可以处理业务逻辑
            # print("用户已经登录,可以处理业务逻辑")
            # print('user:', request.user)
            # print('user 方法:', dir(request.user))
            # login_user = request.user
            # views_logger.info("")
            pass
        else:
            # 尝试使用OIDC登录
            return redirect('/login/oidc/?next=' + request.path)
        return func(request, *args, **kwargs)
    return inner

#  2.装饰到需要鉴权的视图上。
@method_decorator(auth, name='dispatch')  # 启用身份验证,必须登录通过auth函数确定用户登录成功才能访问
class SearchId(View):
  .... 省略get,post函数的复制

 

 

三、遇到的坑

1. 点击Github+ 外链登录后ValueError at /complete/github/   check_hostname requires server_hostname

ValueError at /complete/github/

check_hostname requires server_hostname

原因:SSL 错误, 请查看本机访问github是不是开了VPN代理

解决: 取消代理即可。

2.  启动django 自定义admin 报错  AttributeError: module  XXX  no attribute 'autodiscover'

 File "D:\Python3_study\django04\venv\lib\site-packages\django\contrib\admin\apps.py", line 27, in ready
    self.module.autodiscover()
AttributeError: module 'myadmin' has no attribute 'autodiscover'

 原因:admin后台管理模块需要这个函数,可以对比django默认的admin管理django.contrib.admin模块,里面去找这个函数。

解决方案:到django.contrib.admin模块里翻。发现有这个函数,照抄过来,哈哈~,验证解决启动成功。

3. 将simpleui admin template模板html文件复制过来后,点击Github+ 外链登录后,仍跳回登录界面并无已登录无权限的提示。

没有“您当前以xxxxxxx登录,但是没有这个页面的访问权限。您想使用另外一个账号登录吗?”的提示

原因:simpleui login.html界面没有展示错误提示。

解决方案:将django 默认的django.contrib.admin模块templates/admin/login.html 错误展示代码模块加到simpleui的admin模板login.html中

django.contrib.admin模块templates/admin/login.html 错误展示代码块儿

{% if user.is_authenticated %}
<p class="errornote">
{% blocktranslate trimmed %}
    You are authenticated as {{ username }}, but are not authorized to
    access this page. Would you like to login to a different account?
{% endblocktranslate %}
</p>
{% endif %}

加到simpleui的admin模板login.html的error block块儿位置内

 4. 生产环境遇到oidc登录成功后admin页面报错500

oidc登录成功后admin页面报错500,查看django日志site-packages/social_core/backends/open_id_connect.py模块报错

site-packages/jose.py报错 print decrypt(deserialize_compact(jwt), {'k':key},

原因: 缺 python-jose 包

解决方案:装缺失的依赖包

pip3 install python-jose -i https://mirrors.aliyun.com/pypi/simple/

5. 生产环境OIDC认证发现生成的redirect URL 域名不正确

 原因:django 前端挂了一层nginx ,生成redirect URL 时,域名是根据nginx的proxy_pass 值组合起来的。proxy_pass 不规范。

解决: 需要把前端nginx 的proxy_pass 这个值规范成服务端域名;nginx -s reload 规范配置解决

比如我的错误nginx.conf 配置

 

posted on 2024-06-17 12:10  zhangmingda  阅读(16)  评论(0编辑  收藏  举报

导航