#使用JavaScript调用Horizon中的接口 本文主要解决了以下三个问题:
- 让horizon支持跨域请求(CORS)
- 彻底关闭horizon的CSRF功能
- 支持从headers中读取和设置horizon session_id
##环境
- horizon版本: juno
- django版本: 1.6.11
##horizon设置
-
安装django-cors-headers
pip install django-cors-headers
-
在setting.py中配置django-cors-headers
INSTALLED_APPS = [ [...] 'corsheaders', ] # CorsMiddleware 需要放在第一位 # 注释掉CsrfViewMiddleware中间件,这样还没结束,因为有的view上面加了@csrf_protect装饰器,下面的步骤要把这个装饰给取消掉。 # 注释掉django.contrib.sessions.middleware.SessionMiddleware,用horizon.middleware.SessionMiddleware,horizon.middleware.SessionMiddleware的代码见下文。 MIDDLEWARE_CLASSES = ( 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', # 'django.contrib.sessions.middleware.SessionMiddleware', 'horizon.middleware.SessionMiddleware', [...] ) # CORS # https://github.com/ottoyiu/django-cors-headers CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_CREDENTIALS = True # 允许js发送的request头信息 CORS_ALLOW_HEADERS = ( 'x-requested-with', 'content-type', 'accept', 'origin', 'authorization', 'x-csrftoken', 'SESSION', ) # 允许js额外读取的response头信息 CORS_EXPOSE_HEADERS = ( 'SESSION', ) CORS_ALLOW_METHODS = ( 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS' ) # 将session设置长一点 SESSION_TIMEOUT = 86400
-
彻底关闭CSRF
有些view使用了
@csrf_protect
,只注释django.middleware.csrf.CsrfViewMiddleware
是没用的,好在csrf_protect
提供了一个_dont_enforce_csrf_checks
来跳过认证,这里写个中间件来实现这个功能。(1) 在
django/middleware.py
后追加如下内容:class DisableCSRF(object): def process_request(self, request): setattr(request, '_dont_enforce_csrf_checks', True)
(2) 编辑
settings.py
启用该中间件MIDDLEWARE_CLASSES = ( 'horizon.middleware.DisableCSRF', ... )
-
从header中读取session
编辑
horizon/middleware.py
,在里面放入一个新类SessionMiddleware
是从django.contrib.sessions.middleware.SessionMiddleware
复制过来的,并在里面做了两处修改,一是在process_request
中优先从request header中读取session;二是在process_response
中将session放入response header中。from django.utils.cache import patch_vary_headers from django.utils.http import cookie_date from django.utils.importlib import import_module class SessionMiddleware(object): def process_request(self, request): engine = import_module(settings.SESSION_ENGINE) # 优先从header获取session if request.META.has_key("HTTP_SESSION"): session_key = request.META.get("HTTP_SESSION") else: session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None) request.session = engine.SessionStore(session_key) def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie. """ try: accessed = request.session.accessed modified = request.session.modified except AttributeError: pass else: if accessed: patch_vary_headers(response, ('Cookie',)) if modified or settings.SESSION_SAVE_EVERY_REQUEST: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: request.session.save() # 将session保存到header中去 response["SESSION"] = request.session.session_key response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None) return response
##在JavaScript中调用
代码:
var session_id = '';
function get_session_id() {
return session_id;
}
// callback: 登录成功后回调用
function ossLogin(url, region, username, password, callback) {
// var url = 'http://127.0.0.1:8000/auth/login/';
$.ajax({
type: 'POST',
url: url,
// login登录成功后返回码是302,用complete才能正确识别。
complete: function(xhr) {
session_id = xhr.getResponseHeader('SESSION');
if (callback) {
callback(session_id);
}
},
cache: false,
data: {
region: region,
username: username,
password: password,
x: 223,
y: 24
},
// 有这个才能读取CORS_EXPOSE_HEADERS中的请求头
xhrFields: {
withCredentials: true
}
});
}
登录成功后用get_session_id()
来获取session_id,在后面的请求中加上SESSION
请求头信息,下面给一个callback例子:
var callback = function(session_id) {
console.log(session_id);
$.ajax({
url: 'http://127.0.0.1:8000/do_sth',
headers: {
'SESSION': session_id
},
type: 'GET',
cache: false,
success: function(resp) {
console.log(resp);
}
})
};