更新一些小功能

This commit is contained in:
Leven 2023-01-17 19:56:03 +08:00
parent ba81a90df7
commit e7130fa983
6 changed files with 79 additions and 14 deletions

View File

@ -18,13 +18,16 @@ LDAP_LOGIN_USER = r'修改成自己的'
LDAP_LOGIN_USER_PWD = r'修改为自己的' LDAP_LOGIN_USER_PWD = r'修改为自己的'
# BASE DN账号的查找DN路径例如'DC=abc,DC=com'可以指定到OU之下例如'OU=RD,DC=abc,DC=com'。 # BASE DN账号的查找DN路径例如'DC=abc,DC=com'可以指定到OU之下例如'OU=RD,DC=abc,DC=com'。
# BASE_DN限制得越细搜索用户的目录也就越小一般情况下可以通过SEARCH_FILTER来过滤
BASE_DN = r'修改成自己的' BASE_DN = r'修改成自己的'
# ldap的search_filter如果需要修改请保持用户账号部分为 点位符{} (代码中通过占位符引入账号) # ldap的search_filter如果需要修改请保持用户账号部分为 点位符{0} (代码中通过占位符引入账号)
# 例如AD的用户账号属性是sAMAccountName那么匹配的账号请配置成sAMAccountName={} # 例如AD的用户账号属性是sAMAccountName那么匹配的账号请配置成sAMAccountName={0}
# LDAP中用户账号属性可能是uuid那么匹配的账号请配置成uuid={} # LDAP中用户账号属性可能是uuid那么匹配的账号请配置成uuid={0}
# 默认配置是AD环境的 # 如果想限制用户在哪个组的才能使用,可以写成这样:
SEARCH_FILTER = r'(&(objectclass=user)(sAMAccountName={}))' # r'(&(objectClass=user)(memberof=CN=mis,OU=Groups,OU=OnTheJob,DC=abc,DC=com)(sAMAccountName={0}))', memberof 是需要匹配的组
# 默认配置是AD环境的查询语句可以自行使用Apache Directory Studio测试后再配置
SEARCH_FILTER = r'(&(objectclass=user)(sAMAccountName={0}))'
# 是否启用SSL, # 是否启用SSL,
# 注意AD中必须使用SSL才能修改密码这里被坑了N久...,自行部署下AD的证书服务并颁发CA证书重启服务器生效。具体教程百度一下有很多。 # 注意AD中必须使用SSL才能修改密码这里被坑了N久...,自行部署下AD的证书服务并颁发CA证书重启服务器生效。具体教程百度一下有很多。

View File

@ -30,11 +30,10 @@ LOGGING = {
'disable_existing_loggers': False, 'disable_existing_loggers': False,
'formatters': { 'formatters': {
'verbose': { 'verbose': {
'format': '%(asctime)s %(levelname)s %(pathname)s %(module)s.%(funcName)s %(lineno)d: %(message)s' 'format': '%(asctime)s %(levelname)s %(message)s'
# 日志格式
}, },
'simple': { 'simple': {
'format': '%(asctime)s %(levelname)s %(pathname)s %(module)s.%(funcName)s %(lineno)d: %(message)s' 'format': '%(asctime)s %(levelname)s %(message)s'
}, },
}, },
'filters': { 'filters': {
@ -54,7 +53,7 @@ LOGGING = {
'level': 'DEBUG', 'level': 'DEBUG',
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
# 日志保存文件 # 日志保存文件
'filename': '%s/log.log' % LOG_PATH, 'filename': '%s/all.log' % LOG_PATH,
# 日志格式,与上边的设置对应选择 # 日志格式,与上边的设置对应选择
'formatter': 'verbose' 'formatter': 'verbose'
} }

View File

@ -37,6 +37,13 @@ AD必须使用SSL才能修改密码这里被坑了N久...
### 2023/01/15 -- 更新: ### 2023/01/15 -- 更新:
+ 兼容PC与移动端的显示使用Layui + 兼容PC与移动端的显示使用Layui
+ 修复一些BUG + 修复一些BUG
+ 移除auto-install.sh中的redis部署步骤
+ 抽出应用中的授权验证跳转的代码单独做成一个auth页面可实现选择首页是进入修改密码还是自动跳转重置页面。
+ 调整部分文件说明
+ 添加日志装饰器记录请求日志
+ 优化ad_ops中异常的处理
**如果想在点击应用之后自动跳转到重置页面请将回调接口配置成YOURDOMAIN.com/auth**
## 线上环境需要的基础环境: ## 线上环境需要的基础环境:
@ -118,7 +125,6 @@ chmod +x auto-install.sh
#### 以上配置修改完成之后,则可以通过配置的域名直接访问。 #### 以上配置修改完成之后,则可以通过配置的域名直接访问。
# 手动部署: # 手动部署:
#### 自行安装完python3之后使用python3目录下的pip3进行安装依赖 #### 自行安装完python3之后使用python3目录下的pip3进行安装依赖
#### 我自行安装的Python路径为/usr/local/python3 #### 我自行安装的Python路径为/usr/local/python3

View File

@ -3,12 +3,12 @@ import logging
import os import os
from django.shortcuts import render from django.shortcuts import render
from utils.ad_ops import AdOps from utils.ad_ops import AdOps
from ldap3.core.exceptions import LDAPException
import urllib.parse as url_encode import urllib.parse as url_encode
from utils.format_username import format2username, get_user_is_active, get_email_from_userinfo from utils.format_username import format2username, get_user_is_active, get_email_from_userinfo
from .form import CheckForm from .form import CheckForm
from .utils import code_2_user_detail, ops_account from .utils import code_2_user_detail, ops_account
from django.conf import settings from django.conf import settings
from utils.logger_filter import decorator_request_logger
APP_ENV = os.getenv('APP_ENV') APP_ENV = os.getenv('APP_ENV')
if APP_ENV == 'dev': if APP_ENV == 'dev':
@ -43,6 +43,7 @@ scan_params = PARAMS()
_ops = scan_params.ops _ops = scan_params.ops
@decorator_request_logger(logger)
def auth(request): def auth(request):
home_url = '%s://%s' % (request.scheme, HOME_URL) home_url = '%s://%s' % (request.scheme, HOME_URL)
corp_id = scan_params.corp_id corp_id = scan_params.corp_id
@ -69,6 +70,7 @@ def auth(request):
logger.error('[异常] 请求方法:%s,请求路径%s' % (request.method, request.path)) logger.error('[异常] 请求方法:%s,请求路径%s' % (request.method, request.path))
@decorator_request_logger(logger)
def index(request): def index(request):
""" """
用户自行修改密码/首页 用户自行修改密码/首页
@ -79,10 +81,8 @@ def index(request):
if request.method == 'GET': if request.method == 'GET':
return render(request, 'index.html', locals()) return render(request, 'index.html', locals())
else:
logger.error('[异常] 请求方法:%s,请求路径%s' % (request.method, request.path))
if request.method == 'POST': elif request.method == 'POST':
# 对前端提交的数据进行二次验证,防止恶意提交简单密码或篡改账号。 # 对前端提交的数据进行二次验证,防止恶意提交简单密码或篡改账号。
check_form = CheckForm(request.POST) check_form = CheckForm(request.POST)
if check_form.is_valid(): if check_form.is_valid():
@ -127,6 +127,7 @@ def index(request):
return render(request, msg_template, context) return render(request, msg_template, context)
@decorator_request_logger(logger)
def reset_password(request): def reset_password(request):
""" """
钉钉扫码并验证信息通过之后在重置密码页面将用户账号进行绑定 钉钉扫码并验证信息通过之后在重置密码页面将用户账号进行绑定
@ -242,6 +243,7 @@ def reset_password(request):
return render(request, msg_template, context) return render(request, msg_template, context)
@decorator_request_logger(logger)
def unlock_account(request): def unlock_account(request):
""" """
解锁账号 解锁账号
@ -292,6 +294,7 @@ def unlock_account(request):
return render(request, msg_template, context) return render(request, msg_template, context)
@decorator_request_logger(logger)
def messages(request): def messages(request):
_msg = request.GET.get('msg') _msg = request.GET.get('msg')
button_click = request.GET.get('button_click') button_click = request.GET.get('button_click')

View File

@ -136,6 +136,8 @@ class AdOps(object):
self.__conn() self.__conn()
return True, self.conn.search(BASE_DN, SEARCH_FILTER.format(username), return True, self.conn.search(BASE_DN, SEARCH_FILTER.format(username),
attributes=['sAMAccountName']) attributes=['sAMAccountName'])
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)
@ -149,6 +151,8 @@ class AdOps(object):
self.__conn() self.__conn()
self.conn.search(BASE_DN, SEARCH_FILTER.format(username), attributes=['name']) self.conn.search(BASE_DN, SEARCH_FILTER.format(username), attributes=['name'])
return True, self.conn.entries[0]['name'] return True, self.conn.entries[0]['name']
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)
@ -163,6 +167,8 @@ class AdOps(object):
self.conn.search(BASE_DN, SEARCH_FILTER.format(username), self.conn.search(BASE_DN, SEARCH_FILTER.format(username),
attributes=['distinguishedName']) attributes=['distinguishedName'])
return True, str(self.conn.entries[0]['distinguishedName']) return True, str(self.conn.entries[0]['distinguishedName'])
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)
@ -177,6 +183,8 @@ class AdOps(object):
self.conn.search(BASE_DN, SEARCH_FILTER.format(username), self.conn.search(BASE_DN, SEARCH_FILTER.format(username),
attributes=['userAccountControl']) attributes=['userAccountControl'])
return True, self.conn.entries[0]['userAccountControl'] return True, self.conn.entries[0]['userAccountControl']
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)
@ -190,6 +198,8 @@ class AdOps(object):
if _status: if _status:
try: try:
return True, self.conn.extend.microsoft.unlock_account(user='%s' % user_dn) return True, self.conn.extend.microsoft.unlock_account(user='%s' % user_dn)
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)
else: else:
@ -247,5 +257,7 @@ class AdOps(object):
return True, 'unlocked' return True, 'unlocked'
else: else:
return False, locked_status return False, locked_status
except IndexError:
return False, "AdOps Exception: Connect.search未能检索到任何信息当前账号可能被排除在<SEARCH_FILTER>之外,请联系管理员处理。"
except Exception as e: except Exception as e:
return False, "AdOps Exception: {}".format(e) return False, "AdOps Exception: {}".format(e)

42
utils/logger_filter.py Normal file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from functools import wraps
from traceback import format_exc
def decorator_request_logger(logger):
def decorator(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
try:
rsp = func(request, *args, **kwargs)
logger.info(
f'Request Arguments: {args} {kwargs}')
# logger.info(
# f'Request: {request.META["REMOTE_ADDR"]} {request.method} "{request.META["PATH_INFO"]}'
# f'{request.META["QUERY_STRING"]} {request.META["SERVER_PROTOCOL"]}" {rsp.status_code} {rsp.content}')
logger.info(rsp)
return rsp
except Exception as e:
logger.error(format_exc())
raise e
return wrapper
return decorator
def decorator_default_logger(logger):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
logger.info(f'{args}, {kwargs}')
try:
return func(*args, **kwargs)
except Exception as e:
logger.error(format_exc())
raise e
return wrapper
return decorator