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 阅读(82) 评论(0) 编辑 收藏 举报