这里写自定义目录标题
- 说明
- 需求和思路
- 需求
- 思路
- jupyter开发环境搭建
- 下载
- 开发环境配置
- 安装依赖
- 解决启动错误
- 配置文件
- 项目目录
- 代码修改
- 如何区分用户
- 如何记住用户
- all.py
- session.py
- 在登录时记录用户
- 不同用户不同目录
- 优化体验
- login.py
- notebook/templates/page.html
说明 jupyter 基于tornado web框架。
github地址:https://github.com/1060905996/notebook-master
需求和思路 需求 在系统上集成jupyter供用户使用生成编码。会有多个用户使用jupyter,为避免不同用户误删除其他用户的文件,要求每个用户只能对自己的文件进行增删该查。
思路 为每个用户在配置路劲下创建目录,每个用户只能对自己目录下文件和数据进行增删该查。
jupyter开发环境搭建 项目基于notebook version(7, 0, 0, ‘.dev0’),notebook版本可以在notebook/_version.py下查看。最好在linux下开发,我在windows下无法debug(可能是环境没配置好)。
下载 下载地址: https://github.com/jupyter/notebook , 历史版本:https://github.com/jupyter/notebook/releases。
开发环境配置 参考文档:https://github.com/jupyter/notebook/blob/master/CONTRIBUTING.rst
在pycharm中引入项目,并配置python环境。
安装依赖
cd notebookpip install .npm run build
解决启动错误 将__main__.py 移动到和notebook同等级目录即可解决。
项目启动文件为notebook文件夹下__main__.py,直接在__main__.py中点击[run]启动会报错,需要修改部分文件夹名称。
需要需改的文件夹如下:
notebook/notebook
notebook/nbconvert
对应文件名可以修改为任意名称,并在notebookapp.py中修改对应加载类路径,重新启动main.py。文件夹修改如下:
文章图片
配置文件 为了方便管理,将配置文件jupyter_notebook_config.py放在notebook目录下,并修改配置,
# 允许所有ip访问
c.NotebookApp.allow_origin = '*'
c.NotebookApp.ip='*'
# 设置验证参数token
c.NotebookApp.token = 'mytoken'
# 解决跨域问题
c.NotebookApp.tornado_settings = {
'headers': {
'Content-Security-Policy': "frame-ancestors self *",
}
}
# jupyter工作目录
c.NotebookApp.notebook_dir ='/opt/workspace/jupyter'
# 启动时不在浏览器打开
c.NotebookApp.open_browser = False
# 端口
c.NotebookApp.port = 8001
项目目录
││├─
│││├─
││││├─
├─ notebooke
│├─ auth
││├─ __mian__.py--jupyter notebook password
││├─ login.py-- 登录handler
│││├─ get.method
│││├─ pst.method
││├─ logout.py-- 登出handler
││├─ security.py-- 设置和校验密码
│├─ base
││├─ handlers.py-- 所有handler基础类类
│││├─AuthenticatedHandler.class--用户校验
│││├─IPythonHandler.class--系统设置
│││├─APIHandler.class--服务接口
│││├─Template404.class--模板不存在
│││├─AuthenticatedFileHandler.class--静态文件
││├─
│├─services
│││├─contents
││││├─ fileio.py-- 文件管理基础类
││││├─ filemanage.py-- 文件管理业务实现
││││├─ handlers.py-- 文件管理接口部分
│││││├─ get.method--查询
│││││├─ put.method--保存
│││││├─ post.method--新增文件
│││││├─ delete.method--删除
│││││├─ patch.method--移动或重命名
│├─ session--使框架支持session
│││├─ all.py
│││├─ session
│├─ static--js,css
│├─ template--模板文件
│├─ __main__.py--启动文件
│├─ _version.py--版本
│├─ notebookapp.py--初始化项目
代码修改 如何区分用户 jupyter可以使用token和password登录,但两者都无法对不同用户进行区分。所有在登录中加入user_name参数,用于区分用户。请求示例:http://192.168.5.138:8001/login?token=mytoken&user_name=kevin
如何记住用户 可以使用cookie和session记录登录的用户,个人选择使用session。tornado默认使不支持session的,为此我们需要新增session模块。转自博客:https://www.jianshu.com/p/a14f24700a6b。
all.py
# -*- coding:utf-8 -*-# 存储所有的用户信息
ALL_USER_DIC = {}
session.py
# -*- coding:utf-8 -*-
from .all import ALL_USER_DICclass Session:
def __init__(self, handler):
self.handler = handler
self.random_index_str = Nonedef __get_random_str(self):
import hashlib, time
# 生成md5对象
md = hashlib.md5()# 加入自定义参数来更新md5对象
md.update(bytes(str(time.time()) + ' | own-secret', encoding='utf-8'))# 得到加盐后的十六进制随机字符串来作为用户的索引
return md.hexdigest()def __setitem__(self, key, value):
# 当前session对象中没有对应的索引的时候
if not self.random_index_str:
# 根据处理器对象获得浏览器传来的cookie的值
random_index_str = self.handler.get_secure_cookie("__sson__", None)# 浏览器传来的cookie的值为空的时候, 表示该用户是第一次访问本网站
if not random_index_str:
# 为当前的新用户在当前的session对象中生成索引
self.random_index_str = self.__get_random_str()
# 为当前新用户设置cookie
self.handler.set_secure_cookie('__sson__', self.random_index_str)
# 为当前用户生成保存其相关内容的字典对象
ALL_USER_DIC[self.random_index_str] = {}# 当浏览器传来的cookie不为空的时候
else:
# 浏览器传来的cookie非法的时候
if self.random_index_str not in ALL_USER_DIC.keys():
# 为当前非法用户生产索引
self.random_index_str = self.__get_random_str()
# 仅仅为当前非法用户生成其保存相关内容的字典对象, 避免合法老用户的字典对象被清空
ALL_USER_DIC[self.random_index_str] = {}# 不管当前session对象有没有对应的索引都应该为他设置起相关的信息保存(当然了, 到这一步的时候经过if条件语句的过滤, 剩下来的就是刚刚创建字典对象的新用户或者非法用户, 以及其他合法的老用户了)
ALL_USER_DIC[self.random_index_str][key] = value# 将为以上的新用户或者非法用户设置cookie的操作放在这里本无可厚非. 但是将老用户的cookie也重新设置一遍, 其实是为老用户更新过期时间而做的
self.handler.set_secure_cookie('__sson__', self.random_index_str)def __getitem__(self, key):
# 获取当前用户cookie中保存的索引值, 注意加密方式返回的cookie的值是bytes类型的
self.random_index_str = self.handler.get_secure_cookie('__sson__', None)
# 若索引值为空表示当前用户是新用户, 则直接返回空, 程序到此终止
if not self.random_index_str:
return None# 索引不为空的时候
else:
self.random_index_str = str(self.random_index_str, encoding="utf-8")
# 在服务器端为保存该索引值表示当前用户是非法用户,则直接返回空
current_user = ALL_USER_DIC.get(self.random_index_str, None)
if not current_user:
return None
else:
# 直接返回合法用户指定的key的值, 没有则默认返回空
return current_user.get(key, None)
在登录时记录用户
def get(self):
user_name = self.get_argument("user_name")
self.session["user"] = user_name
不同用户不同目录 方案1:
在调试代码中发现,在获取路径时都会通过fileio.py中_get_os_path获取根目录,然后根据传入path参数拼接路径。可以在方法中获取user_name,根据path,user_name和配置文件拼接参数。缺点:
1. 无法在_get_os_path中获取当前用户
2. 可以在_get_os_path新增user_name参数,但这样需要修改的代码过于多,而且修改后不止是否有其他问题。
方案1被否决。
本来都要放弃jupyter去研究polynote了,但突然灵光一闪想到方案2。
【linux|jupyter 二次开发】方案2:
如果改变用户根目录比较困难,可以限制用户只能对自己目录下文件操作,这样也一样满足需求。根据这个思路调试代码最终找到services/contents/handlers.py,文件中重要方法如下:
get查询文件
put保存文件
post 新增文件
delete删除文件
patch 移动或重命名文件
可以看出tornado是遵守RESTful APi接口规范的。这些方法都有相同的参数[path],path为请求参数,值为操作的目录或文件。_get_os_path(path)返回值为文件在机器上真实路径。
为让每个用户只能操作自己目录,只需要在这些方法中增加校验。判断条件:如当前用户为admin,那么在path参数必须以admin开头,不满足条件即无法修改文件。示例如下:
```
@gen.coroutine
def patch(self, path=''):
"""PATCH renames a file or directory without re-uploading content."""
print("PATCH path =" + path)
if not path.startswith(self.user_root_dir):
raise HTTPError(500, "您没有修改 %s 的权限" % path)
```在方法中分别添加校验,现阶段满足需求要求,并且未发现问题。
优化体验
- 用户在每次登录时看到用户列表,而不是进入自己的文件目录
- 如果用户首次登录,不会针对用户创建新目录
def get(self):
user_name = self.get_argument("user_name")
self.session["user"] = user_name
if not self.contents_manager.dir_exists(user_name):
# 判断用户路径是否存在,如果不存在创建路径
user_path = self.contents_manager._get_os_path(user_name)
os.makedirs(user_path)
if self.current_user:
# 设置登录后默认调转路由
next_url = self.get_argument('next', default=self.default_url + "/"+user_name)
self._redirect_safe(next_url)
else:
self._render()
- 嵌入系统后,jupyter图标占用较多高度,而且logout等按钮需要隐藏。
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- Linux|109 个实用 shell 脚本
- Python专栏|数据分析的常规流程
- JavaScript|JavaScript之DOM增删改查(重点)
- Python|Win10下 Python开发环境搭建(PyCharm + Anaconda) && 环境变量配置 && 常用工具安装配置
- Python绘制小红花
- Pytorch学习|sklearn-SVM 模型保存、交叉验证与网格搜索
- linux笔记|linux 常用命令汇总(面向面试)
- OpenCV|OpenCV-Python实战(18)——深度学习简介与入门示例
- python|8. 文件系统——文件的删除、移动、复制过程以及链接文件