mirror of https://github.com/openspug/spug
A 安全设置增加登录IP绑定设置
parent
3b5ec14185
commit
eb0ab71017
|
@ -8,6 +8,7 @@ import json
|
||||||
KEYS_DEFAULT = {
|
KEYS_DEFAULT = {
|
||||||
'MFA': {'enable': False},
|
'MFA': {'enable': False},
|
||||||
'verify_ip': True,
|
'verify_ip': True,
|
||||||
|
'bind_ip': True,
|
||||||
'ldap_service': {},
|
'ldap_service': {},
|
||||||
'spug_key': None,
|
'spug_key': None,
|
||||||
'api_key': None,
|
'api_key': None,
|
||||||
|
|
|
@ -10,15 +10,18 @@ from libs.mail import Mail
|
||||||
from libs.spug import send_login_wx_code
|
from libs.spug import send_login_wx_code
|
||||||
from libs.mixins import AdminView
|
from libs.mixins import AdminView
|
||||||
from apps.setting.utils import AppSetting
|
from apps.setting.utils import AppSetting
|
||||||
from apps.setting.models import Setting
|
from apps.setting.models import Setting, KEYS_DEFAULT
|
||||||
|
from copy import deepcopy
|
||||||
import platform
|
import platform
|
||||||
import ldap
|
import ldap
|
||||||
|
|
||||||
|
|
||||||
class SettingView(AdminView):
|
class SettingView(AdminView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
data = Setting.objects.all()
|
response = deepcopy(KEYS_DEFAULT)
|
||||||
return json_response([x.to_view() for x in data])
|
for item in Setting.objects.all():
|
||||||
|
response[item.key] = item.real_val
|
||||||
|
return json_response(response)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
form, error = JsonParser(
|
form, error = JsonParser(
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.utils.deprecation import MiddlewareMixin
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from .utils import json_response, get_request_real_ip
|
from .utils import json_response, get_request_real_ip
|
||||||
from apps.account.models import User
|
from apps.account.models import User
|
||||||
|
from apps.setting.utils import AppSetting
|
||||||
import traceback
|
import traceback
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -33,7 +34,8 @@ class AuthenticationMiddleware(MiddlewareMixin):
|
||||||
if access_token and len(access_token) == 32:
|
if access_token and len(access_token) == 32:
|
||||||
x_real_ip = get_request_real_ip(request.headers)
|
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 user.token_expired >= time.time() and user.is_active:
|
||||||
|
if x_real_ip == user.last_ip or AppSetting.get_default('bind_ip') is False:
|
||||||
request.user = user
|
request.user = user
|
||||||
user.token_expired = time.time() + 8 * 60 * 60
|
user.token_expired = time.time() + 8 * 60 * 60
|
||||||
user.save()
|
user.save()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import store from './store';
|
||||||
|
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
const [verify_ip, setVerifyIP] = useState(store.settings.verify_ip);
|
const [verify_ip, setVerifyIP] = useState(store.settings.verify_ip);
|
||||||
|
const [bind_ip, setBindIP] = useState(store.settings.bind_ip);
|
||||||
const [mfa, setMFA] = useState(store.settings.MFA || {});
|
const [mfa, setMFA] = useState(store.settings.MFA || {});
|
||||||
const [code, setCode] = useState();
|
const [code, setCode] = useState();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
@ -36,6 +37,15 @@ export default observer(function () {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleChangeBindIP(v) {
|
||||||
|
setBindIP(v);
|
||||||
|
http.post('/api/setting/', {data: [{key: 'bind_ip', value: v}]})
|
||||||
|
.then(() => {
|
||||||
|
message.success('设置成功');
|
||||||
|
store.fetchSettings()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function handleChangeMFA(v) {
|
function handleChangeMFA(v) {
|
||||||
if (v && !store.settings.spug_key) return message.error('开启MFA认证需要先在基本设置中配置调用凭据');
|
if (v && !store.settings.spug_key) return message.error('开启MFA认证需要先在基本设置中配置调用凭据');
|
||||||
v ? setVisible(true) : handleMFAModify(false)
|
v ? setVisible(true) : handleMFAModify(false)
|
||||||
|
@ -66,13 +76,24 @@ export default observer(function () {
|
||||||
<Form layout="vertical" style={{maxWidth: 500}}>
|
<Form layout="vertical" style={{maxWidth: 500}}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="访问IP校验"
|
label="访问IP校验"
|
||||||
extra="建议开启,校验是否获取了真实的访问者IP,防止因为增加的反向代理层导致基于IP的安全策略失效,当校验失败时会在登录时弹窗提醒。如果你在内网部署且仅在内网使用可以关闭该特性。">
|
extra={<span>建议开启,校验是否获取了真实的访问者IP,防止因为增加的反向代理层导致基于IP的安全策略失效,当校验失败时会在登录时弹窗提醒。如果你在内网部署且仅在内网使用可以关闭该特性。<a
|
||||||
|
href="https://spug.cc/docs/practice/#%E5%AE%89%E5%85%A8%E6%80%A7%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97"
|
||||||
|
target="_blank" rel="noopener noreferrer">为什么没有获取到真实IP?</a></span>}>
|
||||||
<Switch
|
<Switch
|
||||||
checkedChildren="开启"
|
checkedChildren="开启"
|
||||||
unCheckedChildren="关闭"
|
unCheckedChildren="关闭"
|
||||||
onChange={handleChangeVerifyIP}
|
onChange={handleChangeVerifyIP}
|
||||||
checked={verify_ip}/>
|
checked={verify_ip}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="登录IP绑定"
|
||||||
|
extra="强烈建议开启,当开启后会把登录凭证与IP进行绑定,当该登录凭证通过其他IP访问时将自动失效。如非必要,切勿关闭该特性!">
|
||||||
|
<Switch
|
||||||
|
checkedChildren="开启"
|
||||||
|
unCheckedChildren="关闭"
|
||||||
|
onChange={handleChangeBindIP}
|
||||||
|
checked={bind_ip}/>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="登录MFA(两步)认证"
|
label="登录MFA(两步)认证"
|
||||||
style={{marginTop: 24}}
|
style={{marginTop: 24}}
|
||||||
|
|
|
@ -14,11 +14,7 @@ class Store {
|
||||||
fetchSettings = () => {
|
fetchSettings = () => {
|
||||||
this.isFetching = true;
|
this.isFetching = true;
|
||||||
http.get('/api/setting/')
|
http.get('/api/setting/')
|
||||||
.then(res => {
|
.then(res => this.settings = res)
|
||||||
for (let item of res) {
|
|
||||||
this.settings[item.key] = item.value;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => this.isFetching = false)
|
.finally(() => this.isFetching = false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue