使用JavaScript调用Horizon中的接口

#使用JavaScript调用Horizon中的接口 本文主要解决了以下三个问题:

  1. 让horizon支持跨域请求(CORS)
  2. 彻底关闭horizon的CSRF功能
  3. 支持从headers中读取和设置horizon session_id

##环境

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

##horizon设置

  1. 安装django-cors-headers

    	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. 彻底关闭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',
    ...
    )
    
  4. 从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);
        }

    })
};

转载于:https://my.oschina.net/fmnisme/blog/613129

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值