Django项目中使用openpyxl给Excel加密码保护不生效问题求助
问题排查与修复方案
核心问题点
- 混淆了工作簿级保护和工作表级保护的赋值对象,
WorkbookProtection是工作簿级配置,应该赋值给workbook.security属性,而非worksheet.protection openpyxl本身不支持设置Excel文件的打开密码(即整个文件加密必须输入密码才能查看),它仅支持两类保护:- 工作簿结构保护:禁止新增/删除/重命名工作表
- 工作表编辑保护:禁止修改工作表的单元格内容、格式等
- 当前保护配置参数绑定对象错误,导致配置完全未生效
修复代码示例
场景1:仅保护工作簿结构(禁止修改工作表数量、名称等)
def export_member_to_xlsx(request): from openpyxl.workbook.protection import WorkbookProtection import datetime from django.contrib.auth.models import User from django.http import HttpResponse from openpyxl import Workbook user_queryset = User.objects.filter(is_staff=False) response = HttpResponse( content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ) response['Content-Disposition'] = 'attachment; filename={date}-members.xlsx'.format( date=datetime.datetime.now().strftime('%Y-%m-%d'), ) workbook = Workbook() # 工作簿保护正确绑定到workbook的security属性 workbook.security = WorkbookProtection(workbookPassword='password', lockStructure=True) worksheet = workbook.active worksheet.title = 'Members' columns = [ 'User', 'Email', 'First Name', 'Last Name', 'Member Since', 'Subscription Expiry', ] row_num = 1 for col_num, column_title in enumerate(columns, 1): cell = worksheet.cell(row=row_num, column=col_num) cell.value = column_title for member in user_queryset: row_num += 1 row = [ member.username, member.email, member.first_name, member.last_name, member.date_joined, # 请自行确保subscriptions关联逻辑正确,此处保留原有写法 member.subscriptions.current_period_end, ] for col_num, cell_value in enumerate(row, 1): cell = worksheet.cell(row=row_num, column=col_num) cell.value = cell_value workbook.save(response) return response
场景2:保护工作表禁止编辑内容
如果需要禁止用户修改工作表内的单元格内容,使用工作表保护配置即可:
# 省略其他相同逻辑,仅修改worksheet配置部分 worksheet = workbook.active worksheet.title = 'Members' # 工作表保护配置 worksheet.protection.password = 'password' worksheet.protection.enable() # 开启保护 # 可单独配置允许的操作,比如允许用户筛选内容: # worksheet.protection.autoFilter = False
场景3:需要设置整个文件的打开密码
如果需要用户必须输入密码才能打开查看整个Excel文件,openpyxl无法直接实现,你可以借助msoffcrypto-tool在生成xlsx文件后二次加密,示例逻辑如下:
# 先将openpyxl生成的文件写入临时内存 from io import BytesIO import msoffcrypto temp = BytesIO() workbook.save(temp) temp.seek(0) # 加密文件 encrypted = BytesIO() file = msoffcrypto.OfficeFile(temp) file.load_key(password='password') file.encrypt(encrypted) encrypted.seek(0) # 替换HttpResponse的内容 response.write(encrypted.getvalue())
注意事项
- 工作簿结构保护和工作表保护的密码都可以被简单工具绕过,仅用于防止普通用户误操作,不能用于敏感数据加密
- 若需要高安全性的加密,建议生成文件后打包为加密压缩包再提供下载
内容的提问来源于stack exchange,提问作者Biju
相关产品推荐
相关产品推荐

