【Flask】 网站的用户管理

news/2024/5/11 18:45:12/文章来源:https://blog.csdn.net/weixin_33889245/article/details/85938529

网站用户管理

  不知道为什么很多学习Flask的人都是从搭博客开始的(大概是因为那本书的案例是博客,同时对bootstrap支持良好,bootstrap又是twitter开发的吧。。)既然是搭建博客,就免不了要对博客的用户进行管理。我今天照着书整理了下对于这个管理的一些小技巧和小坑。下面来说明一下

  基本的目录结构可以参考Flask项目目录结构那篇文章,就不再多言

■  用密码进行验证

  既然有用户,那么肯定有密码。最朴素的密码认证想法就是把密码明文存在数据库里面,但是这样太不安全了。安装flask时会自动安装的一个依赖包Werkzeug中,有Werkzeug.security可以专门拿来处理密码验证的一些工作。

  Werkzeug的工作原理是把接收到的密码明文通过一定散列算法算出一个散列值,然后把这个值存进数据库。下次用户来验证的时候,就把他提供的明文用同样算法算的散列值,比对数据库中的值是否一致。这至少从端的层面上加强了安全性(不过如果不用HTTPS传输,那么传输过程中密码明文还是会被截获。)。这种对密码的散列操作和验证密码散列值的操作可以一起封装到一个统一的用户类当中去,比如:

from werkzeug.security import generate_password_hash
from werkzeug.security import check_password_hashclass User(db.model):#...    一些字段的设置
password_hash = db.Column(db.String(128),nullable=False)@propertydef password(self):raise AttributeError('password is not a readable attribute')@password.setterdef password(self,password):self.password_hash = generate_password_hash(password)def verify_password(self,password):return check_password_hash(self.password_hash,password)

 

  这里巧妙地运用了python的property装饰器,来把password变成一个只可写不可读的属性。而且password明文都只在内存中做一个中间变量,真正落地到对象的属性中去的是password_hash,也就是一个hash值的变量。经过测试还可以发现,即便两个用户密码设置得一样,只要用户名不同,最终得到的password_hash还是不一样的。

■  用蓝本管理用户相关操作

  在项目结构中介绍过蓝本的用法。在用户管理的时候,我们可以单独的建立一个蓝本来对用户的登入登出以及注册行为做管理。因此自然的,就需要把这个auth蓝本从main蓝本中独立出来成一个单独的目录。比如我按照书上写的一个测试项目的目录是这样的。

  在auth这个蓝本被独立出来之后,为了管理方便,把templates中也按照蓝本分成了几个目录来分别存放不同蓝本的模板文件。在app/__init__.py中注册auth蓝本时的语句是app.register_blueprint(auth, url_prefix='/auth')。后一个参数url_prefix是指在这个蓝本的views中注册的所有路径默认前面都是有一个/auth的。比如在auth/views中我注册了@auth.route('/login'),而项目启动之后访问这个路径要写/auth/login这样子。

  因为蓝本技术的相关信息在flask项目目录结构那张里讲过了,就不再重复。

 

■  利用flask-login来进行用户登录的管理

  真是不得不佩服flask插件的齐全程度,居然还有专门管理用户登录的插件。。在pip install flask-login之后,就可以使用了,这是一个很小的插件。

  首先我们要调整的是用户这个类的模型,也就是models.py中的User这个类。要用flask-login的一些功能,要求这个类实现is_authenticated,is_active,is_anonymous三个属性和get_id()一个方法。当然自己实现起来麻烦的话可以直接让User类继承flask_login.UserMixin这个类即可。由于User类本身是个表模型类,所以它会继承两个父类,也就是class User(UserMixin,db.model)这样子。

  接下来需要改造的是app/__init__.py。和其他的插件一样,flask-login需要在这里进行对app的初始化。简单来说可以像下面这样进行初始化工作:

from flask_login import LoginManager#...其他一些初始化语句

login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'
login_manager.login_message = u'您还没有登录,请先登录'def create_app(config_mode):#...
    login_manager.init_app(app)#...

  请注意flask_login插件导入的不是Login而是LoginManager。然后是在对app初始化之前,login_manager需要进行一些参数的设置,session_protection设置的是对用户会话级别的安全程度,可选值有None,'basic'和'strong'三种。当设置为'strong'时,程序会对客户端IP及浏览器的代理信息做记录,一旦发生异动,就会立刻登出用户,以此保证用户账号的安全性。login_view这个属性跟后续设置的login_required装饰器有关。login_message是指当未登录状态访问@login_required的页面时会强制跳转到login_view指定的页面上来,然后会想这个页面flash(login_message)。这个message的默认值是一串英文提示,换成中文更好。另外要看到这串提示的话必须在前端加上get_flashed_messages()来展现flash消息。

  关于login_required:有些路由,我们期望用户没有登录,即没有确切身份时不能访问。这时就可以在路由的route方法下面加上一个@login_required。这样当用户在未登录状态下试图访问这个路由时,就会跳转到让他登录的界面去。而这个跳转过去到哪个界面就是由login_view属性来决定的。其设置为某个路由的endpoint,即响应函数名作为参数。像上面的话,因为是在auth蓝本中,所以函数名前面还要加上auth.。

 

  接下来,继续回到models.py中。flask-login插件要求使用者必须实现一个回调方法,是一个用@login_manager.user_loader装饰起来的方法。这个方法同时接收一个用户标识符(通常情况下是用户id或类似的主键),然后返回一个用户对象或者None。这个方法主要被用到的时候是,用户请求进入@login_requrired的路由时,程序将加载由这个方法返回的用户对象作为当前已经登录的用户对象。如果返回的是None那么就说明当前没有用户已登录状态的用户,就禁止访问了。

  这里的用户表示符,其实是用户类继承或重载实现的get_id()方法的返回值。UserMixin类的这个方法默认是返回一条记录的主键的值,我们也可以通过重载这个方法来自己制定一个想作为标准判断的值。

  @login_manager.user_loader装饰的这个回调方法之所以写在models里面,大概只是考虑到了在models里面的话不用太复杂的import 关系,只需要from . import login_manager即可(login_manager是在app/__init__.py中定义的)。下面是一个这部分代码的示例:

from . import login_manager@login_manager.user_loader
def load_user(user_id)return User.query.get(user_id)#要根据具体的get_id方法的返回值调整return到底是什么东西。比如get_id方法返回的是字段name的值的话#就要return User.query.filter_by(name=user_id).first()    不要忘了first(),否则返回的仅仅是Query对象,会报错。

 

  实现完这个回调方法之后我们就可以调整forms.py和views.py这两个文件的内容了。在forms.py中,我们可以考虑加上一个登录的表单和一个注册的表单。在登录的表单中加上一个BooleanField的remember_me,这个字段的值可以在后面的视图中用到,后面细说。此外表单本身没什么可说的,可以说下的是表单的前端,为了让前端知道当前是否有用户登录,我们可以在模板里面用{{ current_user.is_authenticated }}这个属性。current_user是由flask-login已经实现的一个对象,就是当前用户。一个常见的实践就是在导航栏的最右边加上一个登录/注销字样:

<ul class="nav navbar-nav">......</ul>
<ul class="nav navbar-nav navbar-right">{% if current_user.is_authenticated %}<li><a href="{{ url_for('auth.logout') }}">注销</a></li>{% else %}<li><a href="{{ url_for('auth.login') }}">登录</a></li>{% endif %}
</ul>

 

  在views中,似乎操作复杂很多,我们既要添加用户登录登出的操作,又要加上新用户注册的一些操作。不过好在既然我们用了flask-login这个东西,就省事很多了。从flask_login中可以import 到login_user和logout_user来一键解决登入登出问题,而注册问题则只是一个数据库写入的操作,只是要在写入之前验证一下用户是不是已经存在之类的。下面是一段示例代码:

 1 @auth.route('/login', methods=['GET', 'POST'])
 2 def login():
 3     loginForm = LoginForm()
 4     if loginForm.validate_on_submit():
 5         user = User.query.filter_by(name=loginForm.name.data).first()
 6         if not user:
 7             flash(u'没有找到相关用户,请先注册')
 8             return redirect(url_for('auth.register'))
 9         elif not user.verify_passwd(loginForm.passwd.data):
10             flash(u'密码错误')
11         else:
12             login_user(user, loginForm.remember_me.data)  # 如果remember_me是True,那么走cookie保存信息,如果是False走session保存信息
13             return redirect(request.args.get('next') or url_for('main.index'))
14
15     return render_template('auth/login.html', form=loginForm)
16
17
18 @auth.route('/logout')
19 @login_required
20 def logout():
21     logout_user()
22     return redirect(url_for('main.index'))
23
24
25 @auth.route('/register', methods=['GET', 'POST'])
26 def register():
27     userForm = UserForm()
28     if userForm.validate_on_submit():
29         name = User.query.filter_by(name=userForm.name.data).first()
30         if name:
31             flash(u'该用户名已经被注册')
32             return redirect(url_for('auth.register'))
33         else:
34             new_user = User(id=userForm.id.data, name=userForm.name.data, age=userForm.age.data,
35                             phone=userForm.phone.data)
36             new_user.password = userForm.passwd.data
37             db.session.add(new_user)
38             db.session.commit()
39             return render_template('auth/success.html')
40     return render_template('auth/register.html', form=userForm)

 

  从上往下看下来,几个注意点。第9行,用了用户实例调用了verify_password方法来验证用户在表单中输入的密码睁不正确。

  第12行,login_user这里给了两个参数,第一个自然是用户实例,第二个则是remember_me的布尔值。当这个值是True,说明用户在表单中的记住我上打了勾,此时程序会把用户名以及用户密码的token以cookie的形式保存到客户端本地,这样下次再开浏览器时就可以直接登录了。如果是False的话那么用户的信息有效的生命周期是会话期间,也就和用flask.session来维护这个信息差不多了。

  第13行,flask-login在从@login_required的页面跳转到login_view的页面来的时候,URL后面会家一串GET请求的参数,其中有next参数,next其实就是记录了在跳转到login_view之前我是从什么页面过来的,这样在login_view成功登录之后我可以借此信息返回原页面。在这里,redirect先尝试能不能返回原页面,不能再返回默认的index页面去。

  第19行,/logout看上去虽然像是一个登出的操作,但是其实质还是需要访问一个页面来完成的。而在登出之前必然是要有已经登录的用户的,所以用了login_required。顺便一提,下面的logout_user()没有参数也没关系。

  第36行,因为在定义User类的时候我们用了@property的方法设置了password属性,所以在这里直接user.password=xxx来赋值是可以的,并且这个赋的值还会自动经过@password.setter函数的处理,变成hash传入passwd_hash这个属性中。不过在此时我们直接user.password去获取密码明文的话还是会报错的。

 ■  利用itsdangerous进行用户注册验证

  上面提到的用户注册还是一个比较朴素的过程。只要有不重名的用户就可以成功注册到数据库中并且进行登录。这么做当然不是很好。回想一下我们平时在注册的时候碰到的场景基本上都是这样的:

  用邮箱名注册(一方面考虑到用户不太容易忘记自己的邮箱是啥,另一方面方便我们对用户进行验证),点击注册之后我们的邮箱会接收到一封验证邮件。在进入验证邮件进行验证之前,我们的账号还处于一个未生效的状态,无法正常登陆。当我们点击了邮件中给出的验证链接之后,账号得到验证,然后就可以正常登录了。

  这方面工作看起来比较复杂,好在flask自带的itsdangerous这个模块可以帮助我们。

  在应用itsdangerous之前,先来看看点击链接验证账号的原理是什么。一般这样的一个链接是http://domainname/auth/confirm/<id>,其中id是用户注册的账号的唯一标识。当访问这个链接,这个路由下的视图函数可以把id作为一个变量读取并处理,根据ID找到用户的账号,然后把这个账号在数据库中的验证标记成已验证即可。当然这样做很不安全,一个解决的办法是把url中的id进行加密。

  itsdangerous对id的加密是基于app.config['SECRET_KEY']的。我们可以用有上下文的shell来进行测试:

#python manage.py shell
>>>from manage import app
>>>from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
>>>s = Serializer(app.config['SECRET_KEY'],expires_in=3600)
>>>token = s.dumps({'confirm':23})
>>>token
>>>一串已经加密的字符串
>>>data = s.loads(token)
>>>data
>>>{u'confirm':23}

 

  上面基本上可以看到itsdangerous.TimedJSONWebSignatureSerializer的用法。创建这样一个Serializer需要一个秘钥参数,另外可以指定过期时间(秒数)。创建完成后用dumps把一个可JSON序列化的python对象变成一串字符串,loads一串字符串可以解析出来这个python对象。这个过程必须在Serializer被创建后expires_in秒数内完成。否则将serializer失效。所谓可JSON序列化,基本上就是说这个对象得是python中的一些基本类型如各种数字类型,字符串,简单字典和简单列表等等。

  这个序列化对象不比hashlib中hash值的操作,那个是只针对字符串且不可逆的。而这个token是可逆的,所以可以拿来被服务器解析,并利用其中的信息。

  这部分生成和验证token的工作又可以放到User这个模型中去,比如按照书上我添加了generate_confirmation_token和confirm两个方法:

class User(UserMixin,db.Model)#...confirmed = db.Column(db.Boolean, default=False)#...def generate_confirmation_token(self,expiration=3600):s = Serializer(app.config['SECRET_KEY'],expires_in=expiration)return s.dumps({'confirm':self.id})def confirm(self, token):s = Serializer(app.config['SECRET_KEY'])  #解析用的不用设置过期时间try:data = s.loads(token)except Exception,e:return Falseif data.get('confirm') != self.id:  #这个判断是说,保证通过token验证的这个id必须是当前使用中用户的id,这样验证就有了密码和加密token的双重保障return Falseself.confirmed = Truedb.session.add(self)
     db.session.commit()
return True

 

  生成token之后,加到链接中,以邮件的形式发送给用户用于验证即可。因为之前没有看flask-email的内容,反正用python自带的email模块也勉强能干这事,这里就不多说了。在视图中,我们要添加上相关的验证token的路由,比如:

####app/auth/views.py#####...

@auth.route('/confirm/<token>')
@login_required    #保证访问这个端点时要有登录用户,结合User.confirm方法中对self.id的判断又要求这个用户不能是其他人只能是要验证的用户本人
def confirm(token):if current_user.confirmed:return redirect(url_for('main.index'))if current_user.confirm(token):flash(u'已完成账号认证')else:flash(u'账号认证失败,凭证不正确或已过期')return redirect(url_for('main.index'))

 

  至此,一个完整的验证过程写好了。不过你可能会疑惑,这样子情况下,未验证但已登录的用户和正常用户有什么差别。答案就是没有差别,因为我们在代码中还没对已登录但未验证的用户做出访问限制。实现这种限制的一个笨办法是在每个路由前都加上一个current_user.confirmed的判断。不过这很麻烦。书上给出的一个解决办法是利用@before_app_request这个回调点。另外对于未验证的用户要提示他去验证,所以还需要在视图中加上一个unconfirmed的路由。加上了这两部分的views如下:

@auth.before_app_request
def before_request():if (current_user.is_authenticated) and (not current_user.confirmed) and (not request.endpoint.startswith('auth')):return redirect(url_for('auth.unconfirmed'))@auth.route('/unconfirmed_user')
@login_required
def unconfirmed():if current_user.confirmed:return redirect(url_for('main.index'))import reflag = re.match('^.+@(\w+?)\.[a-z]+$',current_user.mailAdd).group(1)mail_site = MailSiteMap.get(flag)return render_template('auth/unconfirmed.html',mail_site=mail_site)

 

  下面的那个MailSiteMap是我分析用户的注册邮箱之后把相关邮箱服务提供商的网站以超链接的形式整合到返回的页面中了,一个小改进而已。真正想说的一个是在上面,之前我觉得if的判断条件太长了,想着is_authenticated可以转化成@login_required放在函数外面。但是这里面有个致命错误,就是当用户处于匿名状态(即没有用户登录时)去请求/login界面时,首先调用了@before_app_request。然后重定向到/login界面,然后这个本身又是一个请求,又来调用before_app_request,导致了无限重定向。

 

■  几个面生的属性/方法的利用

  讲到这里,其实已经有点晕了,做个回顾,把用到的一些面生的属性和方法都拿出来回顾下。

  flask.request.endpoint

  flask_login.current_user  //是不是就是@login_manager.load_user返回的那个对象作为current_user的?

  current_user.is_anonymous

  current_user.is_authenticated

  url_for('end.point',key=value,_external=True)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_798149.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu下零基础建站之python基础环境搭建

这篇说的是 ubuntu下 python 基础环境 python2.7&#xff08;为什么是2.7而不是3&#xff1f; tornado 对2.7支持比较好&#xff0c;还有很多包也是支持2.7&#xff09; 1. 输入python 发现不存在 有python3 python3可以。装下python2 2. apt install python (默认python就是2.…

网站部署——文件系统

文件系统方式部署C#网站 一、右键web项目点击发布 发布方法选择文件系统&#xff0c;目标位置自定义。需要注意的是发布到该文件夹的只有包含在项目中的文件夹&#xff0c;如果有未包含在项目中的文件&#xff0c;需要手动复制到目标位置处&#xff08;bin和obj文件夹除外&…

Web网站服务

具体步骤&#xff1a;1&#xff0e;准备工作为了避免发生端口冲突、程序冲突等现象&#xff0c;建议将使用rpm方式安装的httpd及相关依赖包&#xff08;如果有的话&#xff09;卸载。如图所示&#xff1a;2&#xff0e;源码编译及安装插入安装光盘并挂载&#xff0c;进入到光盘…

js 导出pdf上传至oss_Hexo+Github Pages快速实现个人网站(拓展:域名绑定+Netlify自动部署+阿里云OSS)...

关键字&#xff1a;blog, hero, github, netlify, oss, 域名名人写博客是为了火&#xff0c;我们写博客是因为火。—— 那然1 前言为什么要搭博客呢&#xff1f;就像上面那句话&#xff0c;我搭博客就是因为它火&#xff0c;我身边的人都有自己的博客&#xff0c;并用博客记录分…

前端面试中经常问到的问题:如何提高网站性能 总结

1. 使用dns预解析 DNS 请求需要的带宽非常小&#xff0c;但是延迟却有点高&#xff0c;这点在手机网络上特别明显。预读取 DNS 能让延迟明显减少一些&#xff0c;例如用户点击链接时。在某些情况下&#xff0c;延迟能减少一秒钟。 在某些浏览器中这个预读取的行为将会与页面实际…

关于大型网站技术演进的思考(十八)--网站静态化处理—反向代理(10) 【架构师的想法:正向代理和反向代理的区别】

文章来源&#xff1a;http://www.cnblogs.com/sharpxiajun 架构师&#xff1a;夏天的森林 反向代理也是一种可以帮助实现网站静态化的重要技术&#xff0c;今天我就来讲讲反向代理这个主题。那么首先我们要了解下什么是反向代理。和反向代理相对应的是正向代理&#xff0c;正向…

js对cookie的操作,包括清除网站所有cookie

2019独角兽企业重金招聘Python工程师标准>>> function foreach() {var strCookiedocument.cookie;var arrCookiestrCookie.split("; ");for(var i0;i<arrCookie.length;i){var arrarrCookie[i].split("");if(arr.length>0)DelCookie(arr[…

如何拒绝搜索引擎收录自己的网站?

参考1&#xff1a;https://zhidao.baidu.com/question/543972314.html 参考2&#xff1a;https://jingyan.baidu.com/article/e8cdb32b45b3e837042bad7f.html 请复制以下两行代码&#xff1a; User-agent: * Disallow: / 把上面的两行代码保存为Robots.txt文件&#xff0c;放…

网站安全狗V3.2版 增加URL地址全检测功能 保护网站安全

文章来源&#xff1a;http://my.oschina.net/safedog/blog/260885 原 网站安全狗V3.2版 增加URL地址全检测功能 保护网站安全 发表于2年前(2014-05-05 18:15) 阅读&#xff08;134&#xff09; | 评论&#xff08;0&#xff09; 0人收藏此文章, 我要收藏赞012月12日北京OSC源…

python之web开发二:用Python+Django在Eclipse环境下开发web网站【第一个开发的小案例,按照文章可以成功开发web】

http://www.cnblogs.com/linjiqin/p/3595891.html 用PythonDjango在Eclipse环境下开发web网站 一、创建一个项目 如果这是你第一次使用Django&#xff0c;那么你必须进行一些初始设置。也就是通过自动生成代码来建立一个Django项目--一个Django项目的设置集&#xff0c;包含了…

服务器做jsp网站教程视频,linux jsp服务器 视频教程

linux jsp服务器 视频教程 内容精选换一换本节介绍如何构造REST API的请求&#xff0c;并以调用IAM服务的获取用户Token说明如何调用API&#xff0c;该API获取用户的Token&#xff0c;Token可以用于调用其他API时鉴权。您还可以通过这个视频教程了解如何构造请求调用API&#x…

用户评论与问答:对熊掌号SEO的影响!

在传统SEO中&#xff0c;我们经常强调用户体验度&#xff0c;包括&#xff1a;页面的活性与内容质量&#xff0c;它往往是高排名的一个典型代表&#xff0c;简单举例&#xff1a;①博客评论&#xff1a;提高页面更新频率&#xff0c;增强搜索引擎信任度。②问答页面&#xff1a…

Lambda架构与推荐在电商网站实践

Lambda架构与推荐在电商网站实践 2015-11-24 16:36| 发布者: 炼数成金_小数| 查看: 14636| 评论: 0|原作者: 王富平|来自: 高可用架构 摘要: 高可用架构分享及传播在架构领域具有典型意义的文章&#xff0c;本文根据王富平分享记录。转载请注明高可用架构公众号ArchNotes。王富…

网站常见问题1分钟定位 - 如何使用阿里云ARMS轻松重现用户浏览器问题...

客户投诉不断&#xff0c;本地却无法重现&#xff1f; 页面加载较慢是用户经常会反馈的问题&#xff0c;也是前端非常关注的问题之一。但定位、排查解决这类问题就通常会花费非常多的时间&#xff0c;主要原因如下&#xff1a; 页面是在用户端的浏览器上加载执行&#xff0c;复…

部署社交网站

部署社交网站 案例概述 公司的社交网站采用PHP语言开发&#xff0c;为了管理PHP程序员开发的代码&#xff0c;上级领导要求搭建SVN服务器进行版本控制。社交网站的第一个版本部署在LNMP平台上&#xff0c;前端为Nginx&#xff0c;通过fastcgi协议访问后端的PHP服务器。为了保证…

网站被黑跳转到其他网站的解决办法

前几天&#xff0c;有一客户向我们SINE安全公司反映&#xff0c;网站在google上的推广已拒登&#xff0c;说什么网站存在恶意软件或垃圾软件&#xff0c;导致google广告无法上线&#xff0c;还发现网站从google搜索点击进去会直接跳转到其他网站上&#xff0c;直接输入网址不会…

接入高防后为什么有一些网站,APP等会出现延迟,打开速度慢等问题?...

我们常见的一些网站&#xff0c;APP等用户在接入高防后&#xff0c;会出现延迟&#xff0c;打开速度慢等问题&#xff0c;假如出现这样的情况请大家不要惊慌失措&#xff0c;短暂的时间内出现延迟&#xff0c;打开速度慢是正常的。 以下墨者安全给大家分享下原因&#xff1a;1、…

Ajax_实现动态网站的技术、php语法、php接口、前端渲染和后端渲染

1、实现动态网站的技术&#xff08;后端语言&#xff09; php、java&#xff08;jsp和php语言差不多&#xff09;、.net、Nodejs、python。。。 最简单的是学php 2、php基本语法  js中 js代码用script包起来&#xff0c;php中用<?php ?>包起来后&#xff0c;可以放…

后端服务开启gzip_网站怎么开启Gzip压缩?网站开启Gzip压缩的方法,让网站提速数倍!...

什么是Gzip压缩&#xff1f;Gzip压缩一般是指web服务器中的一个功能&#xff0c;当有人来访问这个服务器中的网站时&#xff0c;服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来&#xff0c;一般对纯文本内容可压缩到原大小的40&#xff05;。这样传输就…

dev c++为什么会显示无法更改到模板目录_Kali Linux下Dirb工具web网站目录爆破指南...

在本文中&#xff0c;我们将重点介绍使用Kali Linux工具DIRB的临时目录&#xff0c;并尝试在Web服务器中查找隐藏的文件和目录。一个路径遍历攻击也被称为“目录遍历”目标访问的文件和目录存储在Web根文件夹之外。通过使用带有“ ..”的序列的引用文件及其变体来操纵变量&…