使用JavaScript調用Horizon中的接口

#使用JavaScript調用Horizon中的接口 本文主要解決了如下三個問題:git

  1. 讓horizon支持跨域請求(CORS)
  2. 完全關閉horizon的CSRF功能
  3. 支持從headers中讀取和設置horizon session_id

##環境github

  • horizon版本: juno
  • django版本: 1.6.11

##horizon設置ajax

  1. 安裝django-cors-headersdjango

    pip install django-cors-headers
  2. 在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
  3. 完全關閉CSRFcookie

    有些view使用了@csrf_protect,只註釋django.middleware.csrf.CsrfViewMiddleware是沒用的,好在csrf_protect提供了一個_dont_enforce_csrf_checks來跳過認證,這裏寫個中間件來實現這個功能。session

    (1) 在django/middleware.py後追加以下內容:cors

    class DisableCSRF(object):
    	    def process_request(self, request):
    	        setattr(request, '_dont_enforce_csrf_checks', True)

    (2) 編輯settings.py啓用該中間件dom

    MIDDLEWARE_CLASSES = (
    'horizon.middleware.DisableCSRF',
    ...
    )
  4. 從header中讀取sessionurl

    編輯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);
        }

    })
};
相關文章
相關標籤/搜索