Commit c323519dd4538463109e4b588e0f727fb269575a

Authored by zhenchaozhu
1 parent b6c4f3cc38
Exists in de

m

... ... @@ -0,0 +1,111 @@
  1 +# coding: utf-8
  2 +
  3 +import django.http
  4 +from functools import wraps
  5 +from django.conf import settings
  6 +from django.utils.decorators import available_attrs
  7 +from django.shortcuts import resolve_url
  8 +from django.utils.six.moves.urllib.parse import urlparse
  9 +
  10 +def weapp_django_logout(request, response):
  11 + assert isinstance(request, django.http.HttpRequest)
  12 + assert isinstance(response, django.http.HttpResponse)
  13 + # 请求统一认证登出
  14 + response.delete_cookie('pt')
  15 + response.delete_cookie('pu')
  16 + response.delete_cookie('username')
  17 + return response
  18 +
  19 +def weapp_logout(func=weapp_django_logout):
  20 + """
  21 + Django登出视图函数装饰器
  22 + :param func: 处理登出逻辑的函数,接受request和response两个参数
  23 + :return:
  24 + """
  25 + return auth_decorator_factory(func)
  26 +
  27 +
  28 +def auth_decorator_factory(func=None):
  29 + """
  30 + 登录登出装饰器工厂函数,允许用户自定义外部登录登出函数
  31 + :param func:
  32 + :return:
  33 + """
  34 +
  35 + def decorator(view_func):
  36 + @wraps(view_func)
  37 + def _wrapped_view(request, *args, **kwargs):
  38 + response = view_func(request, *args, **kwargs)
  39 + if func:
  40 + func(request, response)
  41 + return response
  42 +
  43 + return _wrapped_view
  44 +
  45 + return decorator
  46 +
  47 +import json
  48 +
  49 +from django.http import JsonResponse
  50 +
  51 +
  52 +class QCCRJsonResponse(JsonResponse):
  53 + """
  54 + 封装了返回码和信息的JsonResponse类
  55 + """
  56 + def __init__(self, obj=None, code=200, msg="success", status=200, **kwargs):
  57 + data = {"code": code, "msg": msg, "result": json.loads(obj) if isinstance(obj, (str, unicode)) else obj}
  58 + super(QCCRJsonResponse, self).__init__(data=data, status=status, **kwargs)
  59 +
  60 +
  61 +class QCCRErrorResponse(QCCRJsonResponse):
  62 + """
  63 + 请求错误
  64 + """
  65 + def __init__(self, obj=None, code=400, msg="failure", status=400, **kwargs):
  66 + super(QCCRErrorResponse, self).__init__(obj=obj, code=code, msg=msg, status=status, **kwargs)
  67 +
  68 +def user_passes_test(test_func, login_url=None,
  69 + redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect')):
  70 + """
  71 + 本装饰器通过test_func函数,检查views是否通过相应的检测,未通过则跳转到登录页面;test_func函数接受user对象作为参数,通过则返回True
  72 + """
  73 +
  74 + def decorator(view_func):
  75 + @wraps(view_func, assigned=available_attrs(view_func))
  76 + def _wrapped_view(request, *args, **kwargs):
  77 + if test_func(request.user):
  78 + return view_func(request, *args, **kwargs)
  79 + # 如果未通过检查,且为ajax请求,返回403
  80 + if request.is_ajax():
  81 + return QCCRErrorResponse(code=403, msg="用户身份检查失败", status=403)
  82 + # 非ajax请求,跳转到登录页面
  83 + path = request.build_absolute_uri()
  84 + resolved_login_url = resolve_url(login_url or getattr(settings, "QCCR_LOGIN_URL", '/login/'))
  85 + login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
  86 + current_scheme, current_netloc = urlparse(path)[:2]
  87 + if ((not login_scheme or login_scheme == current_scheme) and
  88 + (not login_netloc or login_netloc == current_netloc)):
  89 + path = request.get_full_path()
  90 + from django.contrib.auth.views import redirect_to_login
  91 + return redirect_to_login(path, resolved_login_url, redirect_field_name)
  92 +
  93 + return _wrapped_view
  94 +
  95 + return decorator
  96 +
  97 +
  98 +def weapp_login_required(function=None,
  99 + redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect'),
  100 + login_url=None):
  101 + """
  102 + 登录状态检查装饰器,如果未登录,则直接跳转到登录页面
  103 + """
  104 + actual_decorator = user_passes_test(
  105 + lambda u: u.is_authenticated(),
  106 + login_url=login_url,
  107 + redirect_field_name=redirect_field_name
  108 + )
  109 + if function:
  110 + return actual_decorator(function)
  111 + return actual_decorator
0 112 \ No newline at end of file
... ...
forum/forms/user.py
1 1 # coding: utf-8
2 2  
  3 +import requests
3 4 from django import forms
4 5 from django.contrib.auth import authenticate
5 6 from django.conf import settings
... ... @@ -85,6 +86,9 @@ class LoginForm(forms.Form):
85 86  
86 87 def __init__(self, *args, **kwargs):
87 88 self.user_cache = None
  89 + self.pu = ''
  90 + self.pt = ''
  91 + self.username = ''
88 92 super(LoginForm, self).__init__(*args, **kwargs)
89 93  
90 94 def clean(self):
... ... @@ -92,15 +96,32 @@ class LoginForm(forms.Form):
92 96 password = self.cleaned_data.get('password')
93 97  
94 98 if username and password:
95   - self.user_cache = authenticate(username=username, password=password)
96   - if self.user_cache is None:
97   - raise forms.ValidationError(u'用户名或者密码不正确')
98   - elif not self.user_cache.is_active:
99   - raise forms.ValidationError(u'用户已被锁定,请联系管理员解锁')
  99 + post_params = {
  100 + 'comefrom': 2,
  101 + 'user_name': username,
  102 + 'password': password,
  103 + }
  104 + resp = requests.post(settings.AUTH_DOMAIN, data=post_params, verify=False)
  105 + if resp.status_code == 200:
  106 + rst = resp.json()
  107 + if rst.get('status') == 1:
  108 + data = rst.get('data')
  109 + self.pt = data.get('token')
  110 + self.pu = data.get('suid')
  111 + self.username = username
  112 + else:
  113 + raise forms.ValidationError(u'用户名或者密码不正确')
  114 + else:
  115 + raise forms.ValidationError(u'连接登录中心失败')
  116 +
100 117 return self.cleaned_data
101 118  
102 119 def get_user(self):
103   - return self.user_cache
  120 + return {
  121 + 'pt': self.pt,
  122 + 'pu': self.pu,
  123 + 'username': self.username,
  124 + }
104 125  
105 126  
106 127 class RegisterForm(forms.ModelForm):
... ...
forum/views/user.py
1 1 # coding: utf-8
2 2  
  3 +import requests
3 4 import os, uuid, copy, urllib
4 5 from PIL import Image
5 6 from django.shortcuts import render_to_response, redirect
... ... @@ -128,13 +129,14 @@ def post_login(request):
128 129 if not form.is_valid():
129 130 return get_login(request, errors=form.errors)
130 131  
131   - user = form.get_user()
132   - auth.login(request, user)
133   -
134   - if user.is_staff:
135   - return redirect(request.REQUEST.get('next', '/manage/admin/'))
  132 + user_info = form.get_user()
  133 + pt = user_info.get('pt')
  134 + pu = user_info.get('pu')
  135 + t = redirect(request.REQUEST.get('next', '/'))
  136 + t.set_cookie('pt', pt, 864000)
  137 + t.set_cookie('pu', pu, 864000)
136 138  
137   - return redirect(request.REQUEST.get('next', '/'))
  139 + return t
138 140  
139 141  
140 142 def get_logout(request):
... ...
middlewares/__init__.py
middlewares/session_middleware.py
... ... @@ -0,0 +1,115 @@
  1 +# coding: utf-8
  2 +
  3 +import requests
  4 +from django.conf import settings
  5 +from django.core.cache import caches
  6 +from django.contrib.auth import get_user_model
  7 +from django.contrib.auth.models import AnonymousUser
  8 +
  9 +
  10 +class SessionWithoutLocalUserMiddleware(object):
  11 + """
  12 + 统一权限(认证)中间件,Django系统本地不保存用户的情况使用
  13 + """
  14 +
  15 + def __init__(self):
  16 + self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
  17 + self.cache = caches[self.cache_alias]
  18 + self.UserModel = get_user_model()
  19 +
  20 + def process_request(self, request):
  21 + if hasattr(request, "user") and getattr(request.user, "is_superuser", False):
  22 + # 对于Django系统的admin用户,这里不做任何处理
  23 + pass
  24 + else:
  25 + pt = request.COOKIES.get('pt')
  26 + pu = request.COOKIES.get('pu')
  27 + username = request.COOKIES.get('username')
  28 + if pt and pu:
  29 + # 查询session状态成功的情况,构造QCCRUser
  30 + user = XYTUser(username, pu, pt)
  31 + request.user = user
  32 + else:
  33 + # 拿不到统一认证的session,将当前用户设为匿名用户
  34 + request.user = AnonymousUser()
  35 +
  36 +
  37 +class Manager(object):
  38 +
  39 + def __init__(self):
  40 + self.auth_domain = 'https://api.xiuyetang.com/sys/user/login'
  41 +
  42 +
  43 +class XYTUser(object):
  44 + id = None
  45 + pk = None
  46 + username = ''
  47 + sessionId = ''
  48 + accountNo = ''
  49 + employeeName = ''
  50 + employeeId = 0
  51 + employeeNo = ''
  52 + employeeTel = ''
  53 + deptIds = ''
  54 + email = ''
  55 + entryTime = ''
  56 + uid = ''
  57 + is_staff = False
  58 + is_active = False
  59 + is_superuser = False
  60 + _groups = ''
  61 + _user_permissions = ''
  62 +
  63 + def __init__(self, username, pu, pt):
  64 + self.username = username
  65 + self.id = pu
  66 + self.pk = pu
  67 + self.sessionId = pt
  68 +
  69 + def __str__(self):
  70 + return self.username
  71 +
  72 + def __eq__(self, other):
  73 + return self.username == other.username
  74 +
  75 + def __ne__(self, other):
  76 + return not self.__eq__(other)
  77 +
  78 + def __hash__(self):
  79 + return hash(self.username)
  80 +
  81 + def save(self):
  82 + raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. User info in LDAP.")
  83 +
  84 + def delete(self):
  85 + raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. User info in LDAP.")
  86 +
  87 + def set_password(self, raw_password):
  88 + raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. Password in LDAP.")
  89 +
  90 + def check_password(self, raw_password):
  91 + raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. Password in LDAP.")
  92 +
  93 + def _get_groups(self):
  94 + return self._groups
  95 +
  96 + groups = property(_get_groups)
  97 +
  98 + def _get_user_permissions(self):
  99 + return self._user_permissions
  100 +
  101 + user_permissions = property(_get_user_permissions)
  102 +
  103 + def get_group_permissions(self, obj=None):
  104 + return set()
  105 +
  106 + @property
  107 + def is_anonymous(self):
  108 + return lambda: False
  109 +
  110 + @property
  111 + def is_authenticated(self):
  112 + return lambda: True
  113 +
  114 + def get_username(self):
  115 + return self.username
0 116 \ No newline at end of file
... ...
... ... @@ -16,7 +16,7 @@ DATABASES = {
16 16 'NAME': 'forum', # Or path to database file if using sqlite3.
17 17 # The following settings are not used with sqlite3:
18 18 'USER': 'root',
19   - 'PASSWORD': 'nineteen',
  19 + 'PASSWORD': 'zzc',
20 20 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
21 21 'PORT': '3306', # Set to empty string for default.
22 22 }
... ... @@ -183,12 +183,13 @@ LOGGING = {
183 183 # }
184 184  
185 185 # SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用memcached存储session
  186 +AUTH_DOMAIN = 'https://api.xiuyetang.com/service/user/login'
186 187  
187 188 # 自定义User类
188 189 AUTH_USER_MODEL = 'forum.ForumUser'
189 190  
190 191 # 用户认证BackEnds
191   -# AUTHENTICATION_BACKENDS = ('forum.backends.EmailAuthBackend',)
  192 +AUTHENTICATION_BACKENDS = ('forum.backends.EmailAuthBackend',)
192 193  
193 194 # 默认登陆uri
194 195 LOGIN_URL = '/login/'
... ...