标签:auth 字段 ica als The server eth dfa 安全
开篇引入
1.django和flask的相同点和不同点?
共同点:都是基于wsgi的 不同点: (1) django是一个大而全的框架,提供了方便内置的框架,orm,admin,分页,form,model_form,缓存,信号等很多方便的组件, 我们只要在配置文件中一修改就可以使用。 (2) flask是一个短小精悍,可扩展性非常强,flask适合开发小型的网站,也可以开发大型网站,因为它给我们提供有许多第三方组件,我们就可以结合这些第三方组件集成一个像django一样拥有很多功能的web框架。可定制性非常强。 (3) flask和django最大的不同点:request/session flask是直接导入的,request在全局起作用。 django是依附于request参数,通过参数传导。 两个框架没有优劣之分,具体应用看实际需求。
2.什么是wsgi?
web服务网关接口,wsgi是一个协议,实现该写一个的模块: - wsgiref - werkzeug 实现协议的模块本质上就是socket服务端用于接收用户请求,并处理。 一般web框架基于wsgi实现,这样实现关注点分离,主要负责业务处理。
1 from wsgiref.simple_server import make_server 2 3 def run_server(environ, start_response): 4 start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) 5 return [bytes(‘<h1>Hello, web!</h1>‘, encoding=‘utf-8‘), ] 6 7 8 if __name__ == ‘__main__‘: 9 httpd = make_server(‘127.0.0.1‘, 8000, run_server) 10 httpd.serve_forever()
1 from werkzeug.wrappers import Response 2 from werkzeug.serving import run_simple 3 4 def run_server(environ, start_response): 5 response = Response(‘hello‘) 6 return response(environ, start_response) 7 8 if __name__ == ‘__main__‘: 9 run_simple(‘127.0.0.1‘, 8000, run_server)
from werkzeug.wrappers import Response from werkzeug.serving import run_simple class Flask(object): def __call__(self,environ, start_response): response = Response(‘hello‘) return response(environ, start_response) def run(self): run_simple(‘127.0.0.1‘, 8000, self) app = Flask() if __name__ == ‘__main__‘: app.run()
基础知识
安装:
pip3 install flask
特点: 短小精悍、可扩展强 的一个Web框架。
特色:上下文管理机制
wsgi:web service getway interface web服务网管接口
依赖wsgi:werkzurg
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
def run(environ,start_response):
response = Response(‘hello‘)
return response(environ, start_response)
if __name__ == ‘__main__‘:
run_simple(‘localhost‘, 4000, run)
from werkzeug.wrappers import Request, Response @Request.application def hello(request): return Response(‘Hello World!‘) if __name__ == ‘__main__‘: from werkzeug.serving import run_simple run_simple(‘localhost‘, 4000, hello)
一、配置文件
1.使用:所有配置都在app.config中
PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
class Config(object): DEBUG = False TESTING = False DATABASE_URI = ‘sqlite://:memory:‘ class ProductionConfig(Config): DATABASE_URI = ‘mysql://user@localhost/foo‘ class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True
2.实现原理
指定一个字符串(类的路径),importlib-->getattr 找到这个类把这个类的所有字段(大写)一个一个获取,获取的时候判断isupper(),给一个路径‘settings.Foo‘,可以找到类并获取其中大写的静态字段。
import importlib path = ‘settings.Foo‘ p,c = path.rsplit(‘.‘,maxsplit=1) m = importlib.import_module(p) # m = __import__(p) cls = getattr(m,c) for key in dir(cls): if key.isupper(): print(key,getattr(cls,key))
‘ENV‘: None, ‘DEBUG‘: None, 是否开启DEBUG模式 ‘TESTING‘: False, 是否开启测试模式 ‘PROPAGATE_EXCEPTIONS‘: None, ‘PRESERVE_CONTEXT_ON_EXCEPTION‘: None, ‘SECRET_KEY‘: None, ‘PERMANENT_SESSION_LIFETIME‘: timedelta(days=31), ‘USE_X_SENDFILE‘: False, ‘SERVER_NAME‘: None, ‘APPLICATION_ROOT‘: ‘/‘, ‘SESSION_COOKIE_NAME‘: ‘session‘, ‘SESSION_COOKIE_DOMAIN‘: None, ‘SESSION_COOKIE_PATH‘: None, ‘SESSION_COOKIE_HTTPONLY‘: True, ‘SESSION_COOKIE_SECURE‘: False, ‘SESSION_COOKIE_SAMESITE‘: None, ‘SESSION_REFRESH_EACH_REQUEST‘: True, ‘MAX_CONTENT_LENGTH‘: None, ‘SEND_FILE_MAX_AGE_DEFAULT‘: timedelta(hours=12), ‘TRAP_BAD_REQUEST_ERRORS‘: None, ‘TRAP_HTTP_EXCEPTIONS‘: False, ‘EXPLAIN_TEMPLATE_LOADING‘: False, ‘PREFERRED_URL_SCHEME‘: ‘http‘, ‘JSON_AS_ASCII‘: True, ‘JSON_SORT_KEYS‘: True, ‘JSONIFY_PRETTYPRINT_REGULAR‘: False, ‘JSONIFY_MIMETYPE‘: ‘application/json‘, ‘TEMPLATES_AUTO_RELOAD‘: None, ‘MAX_COOKIE_SIZE‘: 4093, })
二、路由系统
重点:基于装饰器实现
技术点:-functools.wraps(func):保留原函数的原信息
装饰器(带参数)
自定义装饰器放下面
注意事项:
路由设置的两种方式
方式一 @app.route(‘/xxx‘) def index(): return "index" 方式二 def index(): return "index" app.add_url_rule("/xxx",None,index)
-动态路由 /index/<int:nid> def index(nid): print(nid) return ‘index‘
1 rule, URL规则 2 view_func, 视图函数名称 3 endpoint=None, 名称,用于反向生成URL,即: url_for(‘名称‘) 4 methods=None, 允许的请求方式,如:["GET","POST"] 5 strict_slashes=None, 对URL最后的 / 符号是否严格要求, 6 redirect_to=None, 重定向到指定地址 7 8 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={‘k‘:‘v‘}为函数提供参数 9 subdomain=None, 子域名访问
from flask import Flask,url_for app = Flask(__name__) # 步骤一:定制类 from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter): """ 自定义URL匹配正则表达式 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 :param value: :return: """ return int(value) def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 :param value: :return: """ val = super(RegexConverter, self).to_url(value) return val # 步骤二:添加到转换器 app.url_map.converters[‘reg‘] = RegexConverter """ 1.用户发送请求 2.flask内部进行正则匹配 3.调用to_python(正则匹配的结果)方法 4.to_python方法的返回值会交给视图的函数 """ # 步骤三:使用自定义正则 @app.route(‘/index/<reg("\d+"):nid>‘) def index(nid): print(nid,type(nid)) print(url_for(‘index‘,nid=987)) return ‘index‘ if __name__ == ‘__main__‘: app.run()
三、视图
视图:FBV和CBV
技术点:反射
视图函数中获取request或session 方式一:直接找LocalStack获取 from flask.globals import _request_ctx_stack print(_request_ctx_stack.top.request.method) 方式二:通过代理LocalProxy(小东北)获取 from flask import Flask,request print(request.method)
import functools from flask import Flask,views app = Flask(__name__) def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner class UserView(views.MethodView): methods = [‘GET‘] decorators = [wrapper,] def get(self,*args,**kwargs): return ‘GET‘ def post(self,*args,**kwargs): return ‘POST‘ app.add_url_rule(‘/user‘,None,UserView.as_view(‘uuuu‘)) if __name__ == ‘__main__‘: app.run()
四、请求相关
技术点:面向对象的封装
# 请求相关信息 # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host # request.files # obj = request.files[‘the_file_name‘] # obj.save(‘/var/www/uploads/‘ + secure_filename(f.filename))
五、响应相关
技术点:面向对象的封装
响应体:4种
return ‘欢迎使用‘ return jsonify({‘k1‘:‘v1‘}) return render_template(‘xxx.html‘) return redirect(‘/index‘)
定制响应头
obj = make_response(render_template(‘index.html‘)) obj.headers[‘xxxxx‘] = ‘123‘ obj.set_cookie(‘key‘,‘value‘) return obj
示例程序:用户访问限制
@app.route(‘/detail/<int:nid>‘) def detail(nid): if not session.get(‘user‘): return redirect(url_for(‘login‘)) info = STUDENT_DICT[nid] return render_template(‘detail.html‘, info=info)
def auth(func): @wraps(func) def inner(*args,**kwargs): if not session.get(‘user‘): return redirect(url_for(‘login‘)) ret = func(*args,**kwargs) return ret return inner @app.route(‘/index‘) @auth def index(): return render_template(‘index.html‘,stu_dict=STUDENT_DICT) 应用场景:比较少的函数中需要添加额外的功能
@app.before_request def xxxx(): if request.path == ‘/login‘: return None if not session.get(‘user‘): return None return redirect(url_for(‘login‘)) 应用场景:比较多的函数中需要添加额外的功能
六、模板渲染
-基本数据类型:可以执行python语法,如:dict.get() list[‘xx‘]
传入函数
全局定义函数
@app.template_global() def sb(a,b): return a+b @app.template_filter() # 适合if 判断 def db(a,b,c): return a+b+c
模板继承
layout.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% block content %}{% endblock %} </body> </html> tpl.html {% extends ‘layout.html‘ %} {% block content %} {% include ‘form.html‘ %} {% macro ccccc(name,type=‘text‘, value=‘‘) %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" name="提交"> {% endmacro %} {{ ccccc(‘n1‘) }} {{ ccccc(‘n2‘) }} {% endblock %}
<include ‘from.html‘> form.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>sasasasa sasasasasasa</div> </body> </html>
宏
{% macro ccccc(name,type=‘text‘, value=‘‘) %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" name="提交"> {% endmacro %} {{ ccccc(‘n1‘) }} {{ ccccc(‘n2‘) }}
安全
前端:{{ txt|safe }}
后端:Markup(txt)
七、session
原理:加密后放置在用户浏览器的cookie中
流程:
请求到来:flask读取cookie中的session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoiZmVpIn0,将该值解密并反序列化成字典,放入内存以便视图函数使用。 视图函数: @app.route(‘/sess‘) def sess(): print(session.__class__) session[‘k1‘] = 123 session[‘k2‘] = 456 del session[‘k1‘] return ‘Session‘ 请求结束,flask会读取内存中字典的值,进行序列化+加密,写入用户cookie中。
实现原理(源码)
def wsgi_app(self, environ, start_response): """ 1.获取environ并对其进行再次封装 2.从environ中获取名称为session的cookie,解密,反序列化 3.两个东西放到‘某个神奇‘的地方 """ # ctx = RequestContext(self, environ) #self是app对象,evviron是原始数据对象 # ctx.request = Request(environ) # ctx.session = None ctx = self.request_context(environ) error = None try: try: ctx.push() # 4. 执行视图函数 # 5.‘某个神奇’获取session,加密,序列化,写入cookie response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None """ 6.‘某个神奇‘位置清空 """ ctx.auto_pop(error)
闪现(flash): 在session存储一个数据,读取时通过pop将数据删除,形成一种数据只能取一次的效果
from flask import Flask,flash,get_flashed_messages @app.route(‘/page1‘) def page1(): flash(‘临时数据存储‘,‘error‘) flash(‘sasasasa‘,‘error‘) flash(‘sasasas‘,‘info‘) return ‘Session‘ @app.route(‘/page2‘) def page2(): print(get_flashed_messages(category_filter=[‘error‘])) return ‘Session‘
八、中间件
一般不常用,因为它的执行顺序很靠前,无序获取request对象,与请求相关信息难以获得
-用户发起请求时,才执行
class Middleware(object): def __init__(self,old): self.old = old def __call__(self, *args, **kwargs): print(‘前‘) ret = self.old(*args,**kwargs) print(‘后‘) return ret if __name__ == ‘__main__‘: app.wsgi_app = Middleware(app.wsgi_app) app.run()
九、特殊的装饰器
技术点:before_request和after_request的实现原理
before_first_request before_request 视图函数之前,原理是将视图函数放入到一个列表中,循环,如果有返回值停止循环,后面的函数也将不会执行 after_request 视图函数之后,原理是将视图函数放入到一个列表中reverse,循环执行 template_global template_filter errorhandler @app.errorhandler(404) def not_found(arg): print(arg) return ‘404 没找到‘
十、蓝图
(1) 目标:目录结构的划分
(2) 自定义模板、静态文件
admin = Blueprint( ‘admin‘, __name__, template_folder=‘templates‘, static_folder=‘static‘ )
(3) 给某一类url添加前缀变量 app.register_blueprint(admin, url_prefix=‘/admin‘)
(4) 给一类url添加before_request
@app.before_request def x1(): print(‘app.before_request‘)
什么是响应式布局?
技术点:@media
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" /> </head> <body> <div class="row" style="background-color: #28a4c9"> <div class="col-lg-6">.col-lg-6</div> <div class="col-lg-6">.col-lg-6</div> </div> <div class="row" style="background-color: #67b168"> <div class="col-md-6">.col-md-6</div> <div class="col-md-6">.col-md-6</div> </div> <div class="row" style="background-color: red"> <div class="col-sm-6">.col-sm-6</div> <div class="col-sm-6">.col-sm-6</div> </div> <div class="row" style="background-color: gold"> <div class="col-xs-6">.col-xs-6</div> <div class="col-xs-6">.col-xs-6</div> </div> </body> </html>
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body{ margin: 0; } .pg{ width: 100%; background-color: rebeccapurple; } @media (min-width: 666px) { .pg{ background-color: green; } } @media (min-width: 888px) { .pg{ background-color: red; } } </style> </head> <body> <div> <div class="pg">asdfasdf</div> </div> </body> </html>
注:
1. 上下文管理的实现? 当请求到来的时候, flask会把请求相关和session相关信息封装到一个ctx = RequestContext对象中, 会把app和g封装到app_ctx = APPContext对象中去, 通过localstack对象将ctx、app_ctx对象封装到local对象中 获取数据(执行视图函数的时候) 通过导入一个模块,用模块.的方式获取我们想要的数据 实现细节: 通过localproxy对象+偏函数,调用localstack去local中获取对应的响应ctx、app_ctx中封装值 问题:为什么要把ctx = request/session app_ctx = app/g 因为离线脚本需要使用app_ctx 请求结束 调用localstk的pop方法,将ctx和app_ctx移除 2. 为什么把上下文管理分成: - 应用上下文:request/session - 请求上下文: app/g 离线脚本应用 3. Local的作用? 类似于threading.local的作用,但是是他的升级版(greentlet.get_current()) __storage__ = { 1231: {}, 1231: {} } 4. LocalStack作用? 将Local中__storage__的值维护成一下结构: __storage__ = { 1231: {stack:[],}, 1231: {stack:[],} } 5. 为什么要维护成一个栈? 6. 为什么导入request,就可以使用? 每次执行request.xx方法时,会触发LocalProxy对象的__getattr__等方法,由方法每次动态的使用 LocalStack去Local中获取数据
标签:auth 字段 ica als The server eth dfa 安全
原文地址:https://www.cnblogs.com/zhangyafei/p/10204463.html