U improve security

pull/220/head
vapao 2020-10-10 09:49:58 +08:00
parent 4795c9e9ae
commit 3e09794b06
4 changed files with 26 additions and 12 deletions

View File

@ -5,9 +5,11 @@ from django.core.cache import cache
from django.views.generic import View from django.views.generic import View
from django.db.models import F from django.db.models import F
from libs import JsonParser, Argument, human_datetime, json_response from libs import JsonParser, Argument, human_datetime, json_response
from libs.utils import get_request_real_ip
from apps.account.models import User, Role from apps.account.models import User, Role
from apps.setting.models import Setting from apps.setting.models import Setting
from libs.ldap import LDAP from libs.ldap import LDAP
import ipaddress
import time import time
import uuid import uuid
import json import json
@ -155,7 +157,7 @@ def login(request):
Argument('type', required=False) Argument('type', required=False)
).parse(request.body) ).parse(request.body)
if error is None: if error is None:
x_real_ip = request.headers.get('x-real-ip', '') x_real_ip = get_request_real_ip(request.headers)
user = User.objects.filter(username=form.username, type=form.type).first() user = User.objects.filter(username=form.username, type=form.type).first()
if user and not user.is_active: if user and not user.is_active:
return json_response(error="账户已被系统禁用") return json_response(error="账户已被系统禁用")
@ -198,7 +200,7 @@ def handle_user_info(user, x_real_ip):
'access_token': user.access_token, 'access_token': user.access_token,
'nickname': user.nickname, 'nickname': user.nickname,
'is_supper': user.is_supper, 'is_supper': user.is_supper,
'has_real_ip': True if x_real_ip else False, 'has_real_ip': x_real_ip and ipaddress.ip_address(x_real_ip).is_global,
'host_perms': [] if user.is_supper else user.host_perms, 'host_perms': [] if user.is_supper else user.host_perms,
'permissions': [] if user.is_supper else user.page_perms 'permissions': [] if user.is_supper else user.page_perms
}) })

View File

@ -3,7 +3,7 @@
# Released under the AGPL-3.0 License. # Released under the AGPL-3.0 License.
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
from django.conf import settings from django.conf import settings
from .utils import json_response from .utils import json_response, get_request_real_ip
from apps.account.models import User from apps.account.models import User
import traceback import traceback
import time import time
@ -31,7 +31,7 @@ class AuthenticationMiddleware(MiddlewareMixin):
return None return None
access_token = request.headers.get('x-token') or request.GET.get('x-token') access_token = request.headers.get('x-token') or request.GET.get('x-token')
if access_token and len(access_token) == 32: if access_token and len(access_token) == 32:
x_real_ip = request.headers.get('x-real-ip', '') x_real_ip = get_request_real_ip(request.headers)
user = User.objects.filter(access_token=access_token).first() user = User.objects.filter(access_token=access_token).first()
if user and x_real_ip == user.last_ip and user.token_expired >= time.time() and user.is_active: if user and x_real_ip == user.last_ip and user.token_expired >= time.time() and user.is_active:
request.user = user request.user = user

View File

@ -102,3 +102,13 @@ class DateTimeEncoder(json.JSONEncoder):
def generate_random_str(length: int = 4, is_digits: bool = True) -> str: def generate_random_str(length: int = 4, is_digits: bool = True) -> str:
words = string.digits if is_digits else string.ascii_letters + string.digits words = string.digits if is_digits else string.ascii_letters + string.digits
return ''.join(random.sample(words, length)) return ''.join(random.sample(words, length))
def get_request_real_ip(headers: dict):
x_real_ip = headers.get('x-real-ip')
if not x_real_ip:
x_forwarded_for = headers.get('x-forwarded-for')
if not x_forwarded_for:
return ''
x_real_ip = x_forwarded_for.split(',')[0]
return x_real_ip

View File

@ -4,10 +4,10 @@
* Released under the AGPL-3.0 License. * Released under the AGPL-3.0 License.
*/ */
import React from 'react'; import React from 'react';
import {Form, Input, Icon, Button, Tabs, Modal} from 'antd'; import { Form, Input, Icon, Button, Tabs, Modal } from 'antd';
import styles from './login.module.css'; import styles from './login.module.css';
import history from 'libs/history'; import history from 'libs/history';
import {http, updatePermissions} from 'libs'; import { http, updatePermissions } from 'libs';
import logo from 'layout/logo-spug-txt.png'; import logo from 'layout/logo-spug-txt.png';
import envStore from 'pages/config/environment/store'; import envStore from 'pages/config/environment/store';
import appStore from 'pages/config/app/store'; import appStore from 'pages/config/app/store';
@ -46,7 +46,9 @@ class LoginIndex extends React.Component {
className: styles.tips, className: styles.tips,
content: <div> content: <div>
未能获取到客户端的真实IP无法提供基于请求来源IP的合法性验证详细信息请参考 未能获取到客户端的真实IP无法提供基于请求来源IP的合法性验证详细信息请参考
<a target="_blank" href="https://spug.dev" rel="noopener noreferrer">官方文档</a> <a target="_blank"
href="https://spug.dev/docs/practice/#%E5%AE%89%E5%85%A8%E6%80%A7%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97"
rel="noopener noreferrer">官方文档</a>
</div>, </div>,
onOk: () => this.doLogin(data) onOk: () => this.doLogin(data)
}) })
@ -122,11 +124,11 @@ class LoginIndex extends React.Component {
<a className={styles.links} title="官网" href="https://www.spug.dev" target="_blank" <a className={styles.links} title="官网" href="https://www.spug.dev" target="_blank"
rel="noopener noreferrer">官网</a> rel="noopener noreferrer">官网</a>
<a className={styles.links} title="Github" href="https://github.com/openspug/spug" target="_blank" <a className={styles.links} title="Github" href="https://github.com/openspug/spug" target="_blank"
rel="noopener noreferrer"><Icon type="github" /></a> rel="noopener noreferrer"><Icon type="github"/></a>
<a title="文档" href="https://www.spug.dev/docs/about-spug/" target="_blank" <a title="文档" href="https://www.spug.dev/docs/about-spug/" target="_blank"
rel="noopener noreferrer">文档</a> rel="noopener noreferrer">文档</a>
</div> </div>
<div style={{color: 'rgba(0, 0, 0, .45)'}}>Copyright <Icon type="copyright" /> 2020 By OpenSpug</div> <div style={{color: 'rgba(0, 0, 0, .45)'}}>Copyright <Icon type="copyright"/> 2020 By OpenSpug</div>
</div> </div>
</div> </div>
) )