背景:
在部分的业务过程中,我们服务器上的部分静态资源文件是需要对应权限才可以进行访问。所以我们在使用nginx提供web服务的时候,需要限制部分的静态资源文件只允许内部进行访问,内部判断相关访问文件的权限之后再进行相关文件服务的提供。
实践:
1.首先搭建一个测试使用的静态文件放置root /data/app/html/:
<html>
<head>
<title>protect</title>
<head>
</body>
<h1>protect</h1>
<div style="width:500px; height: 500px; border: 1px solid #ccc;">
<img style="width:500px; height: 500px; border: 1px solid #ccc;" src='../upload/0.jpeg'>
</div>
<img src='/static/001.txt'>
<img src='/static/s.png'>
</body>
</html>
2.新增nginx的web.conf虚拟主机文件:
server {
listen 80;
server_name 192.168.182.155;
root /data/app/html/; #静态文件项目的目录
location / {
index Index.html index.html;
#proxy_pass http://192.168.182.155:8089;
}
location ~* ^/(upload)/{
#proxy_pass http://www.baidu.com;
#
#internal;
#sendfile on;
#tcp_nopush on;
#add_header 'Access-Control-Allow-Origin' '*';
#add_header 'Access-Control-Allow-Credentials' 'true';
#add_header 'Cache-Control no-cache' 'no-store';
#proxy_pass http://192.168.182.155:8089;
#rewrite ^/ http://192.168.182.155:8089;
#proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#alias /data/app/html2/static/$1; #当请求”/upload/0.jpeg”将返回”/data/app/html2/static/0.jpeg”
#internal;
#proxy_redirect off;
#proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_pass http://192.168.182.155:8089;
internal; # 限制内部访问的关键字段
alias /data/app/html2/static/$1; //文件可以放到别的目录
}
}
3.重启启动 nginx -s reload
4.查询页面访问的情况: curl 192.168.182.155
5.当访问: 192.168.182.155/upload/XXXXXX的时候会匹配到 location ~* ^/(upload)/
6.准备相关的bottle服务/data/app/xianzhi/app.py:
#!/usr/bin/evn python
# coding=utf-8
# 导入程序需要的日志包模块
import logging
import sys
from functools import wraps
from beaker.middleware import SessionMiddleware
from bottle import route, run, TEMPLATE_PATH, default_app, static_file, get, error, request, redirect, template, response, HTTPResponse
import os
# 导入自定义的路由视图模块,即URL路径
# 获取本脚本所在的路径
pro_path = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(pro_path)
# 定义static路径,即静态资源路径,如css,js,及样式中用到的图片等
static_path = os.path.join(pro_path, 'static')
# 定义模板路径
TEMPLATE_PATH.append(os.path.join(pro_path, 'template'))
# 创建日志目录
if not os.path.exists('log'):
os.mkdir('log')
# 定义日志目录
log_path = ('/'.join((pro_path, 'log')))
# 定义日志输出格式
logging.basicConfig(level=logging.ERROR,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename="%s/error_log" % log_path,
filemode='a')
# 设置session参数
session_opts = {
'session.type': 'file',
'session.cookei_expires': 3600,
'session.data_dir': '/tmp/sessions',
'sessioni.auto': True
}
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
session = request.environ.get('beaker.session') # 获取session
if not session.get('login'):
return '还没登入!!!'
return f(*args, **kwargs)
return decorated_function
@error(404)
def error404(error):
"""定制错误页面"""
return '404'
@get('/favicon.ico')
def favicon():
pass
@route('/')
def index():
return 'index'
@get('/user/')
def user():
# return 'sdasda'
return template('upload')
# @route('/static/<filepath:path>')
# def server_static(filepath):
# """设置静态内容路由"""
#
# print('静态路由:', static_path)
# return static_file(filepath, root=static_path)
# [root@bogon ~]# curl -I http://192.168.182.155/upload/0.jpeg
# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
# # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
# response.headers['X-asdas'] = 'asasaaa'
# response.headers['X-Accel-Redirect'] = '/upload/%s' % filepath
# response.headers['Content-Disposition'] = 'attachment; filename=asasas'
# print('/upload/%s' % filepath)
# print('静态路由1:', static_path)
# print('静态路由2:', '/data/app/xianzhi'+'/upload/%s' % filepath)
# return static_file(filepath, root='/data/app/xianzhi/upload/')
# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
# # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
# # response.headers['X-asdas'] = 'asasaaa'
# response.headers['X-Accel-Redirect'] = '/data/app/xianzhi'+'/upload/%s' % filepath
# response.headers['Content-Disposition'] = 'attachment; filename=asasas'
# print('/upload/%s' % filepath)
# print('静态路由1:', static_path)
# print('静态路由2:', '/data/app/xianzhi'+'/upload/%s' % filepath)
# return static_file(filepath, root='/data/app/xianzhi/upload/')
# # 这个方法是可行的!!!
# @route('/upload/<filename:re:.*\.jpeg>')
# def send_image(filename):
# # response.set_header('Content-Language', 'en')
# # response.set_header('X-Accel-Redirect', '/upload/%s' % filename)
# response.set_header('X-Sendfile', '/upload/%s' % filename)
# response.set_header('Content-Type', 'application/jpeg')
# response.set_header('X-Accel-Redirect', '/upload/%s'% filename)
# fsize = os.path.getsize('/data/app/xianzhi' + '/upload/%s' % filename)
# # response.set_header('Content-Disposition', 'attachment; filename=' + '/upload/%s' % filename)
# # print('文件大小:', fsize)
# response.set_header('Content-Length', fsize) #
# # response.set_header('Content-Disposition', "attachment; filename=\"" + filename + "\";")
# print('成功了吗!!-----------------!')
# return response
# return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')
# 这个方法是可行的!!!
@route('/upload/<filename:re:.*\.rar>')
def send_image(filename):
# response.set_header('Content-Language', 'en')
response.set_header('X-Accel-Redirect', '/upload/%s' % filename)
response.set_header('X-Sendfile', '/upload/%s' % filename)
# response.set_header('Content-Type', 'application/octet-stream')
response.set_header('Content-Disposition', 'attachment;')
print('成功了吗rar!!!')
# return response
# return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')
@route('/upload/<filename:re:.*\.jpeg>')
def send_image(filename):
# response.set_header('Content-Language', 'en')
# response.set_header('X-Accel-Redirect', '/upload/%s' % filename)
# response.set_header('X-Sendfile','/upload/%s' % filename)
# response.set_header('Content-Type', 'application/octet-stream')
# response.set_header('Content-Disposition', 'attachment;')
print('成功了吗22222!!!')
return response
# return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')
# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
# # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
# # response.headers['X-asdas'] = 'asasaaa'
#
# fsize = os.path.getsize('/data/app/xianzhi' + '/upload/%s' % filepath)
# print('文件大小:', fsize)
# response.headers['Content-Length'] = fsize
# response.headers['Content-Disposition'] = 'attachment; filename=/upload/' + filepath
# response.headers['Content-Type'] = 'application/octet-stream'
# response.headers['X-Accel-Redirect'] = '/upload/%s' % filepath
# response.headers['X-Sendfile'] = '/upload/%s' % filepath
# print('/upload/%s' % filepath)
# print('静态路由1:', static_path)
# print('静态路由2:', '/data/app/xianzhi' + '/upload/%s' % filepath)
# # return
# # return HTTPResponse(body, **headers)
# # return response
# return static_file(filepath, root='/data/app/xianzhi/upload/')
# header('Content-Disposition: attachment; filename="(希望客户下载到的文件名)"');
# @get('/upload/<filepath:path>')
# @login_required
# def upload(filepath):
# print(filepath)
# response['Content-Type'] = 'application/jpg'
# response['X-Accel-Redirect'] = '/vagrant/upload/%s' % filepath
#
# print(response)
# return response
@route('/login')
def login():
# session['login'] = True
s = request.environ.get('beaker.session') # 如果帐号密码正确,则获取环境变量中的beaker.session对象,并赋值给s,然后我们就可以用字典的方式,往s里面添加一些我们要存进去的数据,如帐号名,帐号id,权限等等
s['login'] = True
s.save()
s = request.environ.get('beaker.session') # 获取session
login = s.get('login', None) # 从session中获取Key为user的值,是上面登陆的时候保存进来
print(login)
return 'log in'
@route('/logout')
def logout():
# session['login'] = False
s = request.environ.get('beaker.session') # 如果帐号密码正确,则获取环境变量中的beaker.session对象,并赋值给s,然后我们就可以用字典的方式,往s里面添加一些我们要存进去的数据,如帐号名,帐号id,权限等等
s['login'] = False
s.save()
return 'log out'
# 函数主入口
if __name__ == '__main__':
app_argv = SessionMiddleware(default_app(), session_opts)
run(app=app_argv, host='127.0.0.1', port=8888, debug=True, reloader=True)
else:
application = SessionMiddleware(default_app(), session_opts)
# 直接的启动程序
# run(host='localhost', port=8080, reloader=True, debug=True)
# if __name__ == '__main__':
# app = default_app()
# app = SessionMiddleware(app, session_opts)
# run(app=app, host='127.0.0.1', port=8080, debug=True, server='gevent')
# else:
# application = SessionMiddleware(default_app(), session_opts)
#
# # # 函数主入口
# # if __name__ == '__main__':
# # run(host='127.0.0.1', port=8090, debug=True, reloader=True)
# # else:
# # pass
7:使用 uwsgi 启动app.py,对应的配置文件app_uwsgi.ini:
[uwsgi]
socket = 127.0.0.1:8086
chdir = /data/app/xianzhi/
wsgi-file = /data/app/xianzhi/app.py
limit-as = 512
reload-on-as = 256
reload-on-rss = 192
processes = 2
max-requests = 2000
pythonpath = /data/app/xianzhi/
log-maxsize = 10000000
madisable-logging = true
master = true
vacuum = true
no-orphans = true
7:使用 uwsgi 启动app.py 方式:
# cd /data/app/xianzhi
# uwsgi app_uwsgi.ini
因为使用了uwsgi启动,需要使用sockie的方式进行处理请求:
8:配置web_app.conf,用户通过nginx 访问 uwsgi开启的服务
server {
listen 8089;
server_name 192.168.182.155;
root /data/app/xianzhi/;
location / {
include uwsgi_params;
uwsgi_param UWSGI_PYHOME /data/app/xianzhi;
uwsgi_param UWSGI_CHDIR /data/app/xianzhi;
uwsgi_param UWSGI_SCRIPT app; # 对应main.py
uwsgi_pass 127.0.0.1:8086;
client_max_body_size 50m;
proxy_connect_timeout 1; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 120; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 120; #连接成功后,后端服务器响应时间(代理接收超时)
}
}
8: 配置静态页面的访问路径,通过代理指向到192.168.182.155:8089
9:启动浏览器刷192.168.182.155 观察是否访问到了后端服务接口
补充说明:
图示说明:bottle 提供的static_file也提供了对应X-Sendfile的方式进行静态文件的处理
再非缓存情况206状态的情况下,他直接的显示调用了