diff --git a/common/auth.py b/common/auth.py index bae340f8aa..2721af423d 100644 --- a/common/auth.py +++ b/common/auth.py @@ -3,6 +3,7 @@ import traceback import simplejson as json +from django.contrib.sessions.backends.db import SessionStore from django.contrib.auth import authenticate, login, logout from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ValidationError @@ -12,7 +13,7 @@ from common.config import SysConfig from common.utils.ding_api import get_ding_user_id -from sql.models import Users, ResourceGroup +from sql.models import Users, ResourceGroup, TwoFactorAuthConfig logger = logging.getLogger('default') @@ -64,7 +65,6 @@ def authenticate(self): if authenticated_user: # ldap 首次登录逻辑 init_user(authenticated_user) - login(self.request, authenticated_user) return {'status': 0, 'msg': 'ok', 'data': authenticated_user} else: return {'status': 1, 'msg': '用户名或密码错误,请重新输入!', 'data': ''} @@ -90,7 +90,6 @@ def authenticate(self): if authenticated_user: if not authenticated_user.last_login: init_user(authenticated_user) - login(self.request, authenticated_user) return {'status': 0, 'msg': 'ok', 'data': authenticated_user} user.failed_login_count += 1 user.last_login_failed_at = datetime.datetime.now() @@ -104,11 +103,25 @@ def authenticate_entry(request): new_auth = ArcheryAuth(request) result = new_auth.authenticate() if result['status'] == 0: - # 从钉钉获取该用户的 dingding_id,用于单独给他发消息 - if SysConfig().get("ding_to_person") is True and "admin" not in request.POST.get('username'): - get_ding_user_id(request.POST.get('username')) - - result = {'status': 0, 'msg': 'ok', 'data': None} + authenticated_user = result['data'] + twofa_enabled = TwoFactorAuthConfig.objects.filter(user=authenticated_user) + if twofa_enabled: + # 用户设置了2fa的情况需要进一步验证 + auth_type = twofa_enabled[0].auth_type + # 设置无登录状态cookie + s = SessionStore() + s['user'] = authenticated_user.username + s['auth_type'] = auth_type + s.set_expiry(300) + s.create() + result = {'status': 0, 'msg': 'ok', 'data': s.session_key} + else: + # 未设置2fa直接登录 + login(request, authenticated_user) + # 从钉钉获取该用户的 dingding_id,用于单独给他发消息 + if SysConfig().get("ding_to_person") is True and "admin" not in request.POST.get('username'): + get_ding_user_id(request.POST.get('username')) + result = {'status': 0, 'msg': 'ok', 'data': None} return HttpResponse(json.dumps(result), content_type='application/json') diff --git a/common/middleware/check_login_middleware.py b/common/middleware/check_login_middleware.py index 3707169e73..ba4b6c3138 100644 --- a/common/middleware/check_login_middleware.py +++ b/common/middleware/check_login_middleware.py @@ -5,6 +5,7 @@ IGNORE_URL = [ '/login/', + '/login/2fa/', '/authenticate/', '/signup/', '/api/info' diff --git a/common/templates/2fa.html b/common/templates/2fa.html new file mode 100644 index 0000000000..88cdd4e8ca --- /dev/null +++ b/common/templates/2fa.html @@ -0,0 +1,122 @@ + + + + Archery - 两步验证 + {% load static %} + + + + + + + + + + +
+
+ +
+
+ + +
+

© Archery (v{{ archery_version }})

+
+ + + + + + + diff --git a/common/templates/base.html b/common/templates/base.html index 0b37ef1288..7fe28b4268 100644 --- a/common/templates/base.html +++ b/common/templates/base.html @@ -73,6 +73,7 @@ 管理后台 {% endif %} +
  • 两步验证
  • 修改密码
  • 退出
  • @@ -279,6 +280,63 @@ + + + + + +
    @@ -319,6 +377,156 @@ } }; +