增强后台安全限制

优化登录判断机制
移除冗余代码

(cherry picked from commit 7e6314a701)
pull/413/MERGE
Karson 2023-06-20 11:51:59 +08:00 committed by F4nniu
parent b44f3791b1
commit 57c2f23106
6 changed files with 92 additions and 33 deletions

View File

@ -70,6 +70,8 @@ class Index extends Backend
if ($this->auth->isLogin()) {
$this->success(__("You've logged in, do not login again"), $url);
}
//保持会话有效时长,单位:小时
$keeyloginhours = 24;
if ($this->request->isPost()) {
$username = $this->request->post('username');
$password = $this->request->post('password');
@ -95,7 +97,7 @@ class Index extends Backend
$this->error($validate->getError(), $url, ['token' => $this->request->token()]);
}
AdminLog::setTitle(__('Login'));
$result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
$result = $this->auth->login($username, $password, $keeplogin ? $keeyloginhours * 3600 : 0);
if ($result === true) {
Hook::listen("admin_login_after", $this->request);
$this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $username, 'avatar' => $this->auth->avatar]);
@ -113,6 +115,7 @@ class Index extends Backend
}
$background = Config::get('fastadmin.login_background');
$background = $background ? (stripos($background, 'http') === 0 ? $background : config('site.cdnurl') . $background) : '';
$this->view->assign('keeyloginhours', $keeyloginhours);
$this->view->assign('background', $background);
$this->view->assign('title', __('Login'));
Hook::listen("admin_login_init", $this->request);

View File

@ -129,7 +129,7 @@ class Admin extends Backend
exception(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
$params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
$params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。
$result = $this->model->validate('Admin.add')->save($params);
if ($result === false) {
@ -183,7 +183,7 @@ class Admin extends Backend
exception(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
$params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
} else {
unset($params['password'], $params['salt']);
}
@ -192,7 +192,7 @@ class Admin extends Backend
$adminValidate->rule([
'username' => 'require|regex:\w{3,30}|unique:admin,username,' . $row->id,
'email' => 'require|email|unique:admin,email,' . $row->id,
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id,
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id,
'password' => 'regex:\S{32}',
]);
$result = $row->validate('Admin.edit')->save($params);

View File

@ -65,5 +65,6 @@ return [
'Forum' => '交流社区',
'QQ qun' => 'QQ交流群',
'Captcha' => '验证码',
'The duration of the session is %s hours' => '设定会话有效时长为%s小时',
'Security tips' => '<i class="fa fa-warning"></i> 安全提示为了你的后台安全请勿将后台管理入口设置为admin或admin.php',
];

View File

@ -51,7 +51,7 @@ class Auth extends \fast\Auth
$this->setError('Please try again after 1 day');
return false;
}
if ($admin->password != md5(md5($password) . $admin->salt)) {
if ($admin->password != $this->getEncryptPassword($password, $admin->salt)) {
$admin->loginfailure++;
$admin->save();
$this->setError('Password is incorrect');
@ -63,7 +63,8 @@ class Auth extends \fast\Auth
$admin->token = Random::uuid();
$admin->save();
Session::set("admin", $admin->toArray());
$this->keeplogin($keeptime);
Session::set("admin.safecode", $this->getEncryptSafecode($admin));
$this->keeplogin($admin, $keeptime);
return true;
}
@ -101,7 +102,7 @@ class Auth extends \fast\Auth
return false;
}
//token有变更
if ($key != md5(md5($id) . md5($keeptime) . md5($expiretime) . $admin->token . config('token.key'))) {
if ($key != $this->getKeeploginKey($admin, $keeptime, $expiretime)) {
return false;
}
$ip = request()->ip();
@ -110,8 +111,9 @@ class Auth extends \fast\Auth
return false;
}
Session::set("admin", $admin->toArray());
Session::set("admin.safecode", $this->getEncryptSafecode($admin));
//刷新自动登录的时效
$this->keeplogin($keeptime);
$this->keeplogin($admin, $keeptime);
return true;
} else {
return false;
@ -124,18 +126,64 @@ class Auth extends \fast\Auth
* @param int $keeptime
* @return boolean
*/
protected function keeplogin($keeptime = 0)
protected function keeplogin($admin, $keeptime = 0)
{
if ($keeptime) {
$expiretime = time() + $keeptime;
$key = md5(md5($this->id) . md5($keeptime) . md5($expiretime) . $this->token . config('token.key'));
$data = [$this->id, $keeptime, $expiretime, $key];
Cookie::set('keeplogin', implode('|', $data), 86400 * 7);
$key = $this->getKeeploginKey($admin, $keeptime, $expiretime);
Cookie::set('keeplogin', implode('|', [$admin['id'], $keeptime, $expiretime, $key]), $keeptime);
return true;
}
return false;
}
/**
* 获取密码加密后的字符串
* @param string $password 密码
* @param string $salt 密码盐
* @return string
*/
public function getEncryptPassword($password, $salt = '')
{
return md5(md5($password) . $salt);
}
/**
* 获取密码加密后的自动登录码
* @param string $password 密码
* @param string $salt 密码盐
* @return string
*/
public function getEncryptKeeplogin($params, $keeptime)
{
$expiretime = time() + $keeptime;
$key = md5(md5($params['id']) . md5($keeptime) . md5($expiretime) . $params['token'] . config('token.key'));
return implode('|', [$this->id, $keeptime, $expiretime, $key]);
}
/**
* 获取自动登录Key
* @param $params
* @param $keeptime
* @param $expiretime
* @return string
*/
public function getKeeploginKey($params, $keeptime, $expiretime)
{
$key = md5(md5($params['id']) . md5($keeptime) . md5($expiretime) . $params['token'] . config('token.key'));
return $key;
}
/**
* 获取加密后的安全码
* @param $params
* @return string
*/
public function getEncryptSafecode($params)
{
return md5(md5($params['username']) . md5(substr($params['password'], 0, 6)) . config('token.key'));
}
public function check($name, $uid = '', $relation = 'or', $mode = 'url')
{
$uid = $uid ? $uid : $this->id;
@ -180,13 +228,19 @@ class Auth extends \fast\Auth
if (!$admin) {
return false;
}
$my = Admin::get($admin['id']);
if (!$my) {
return false;
}
//校验安全码,可用于判断关键信息发生了变更需要重新登录
if (!isset($admin['safecode']) || $this->getEncryptSafecode($my) !== $admin['safecode']) {
$this->logout();
return false;
}
//判断是否同一时间同一账号只能在一个地方登录
if (Config::get('fastadmin.login_unique')) {
$my = Admin::get($admin['id']);
if (!$my || $my['token'] != $admin['token']) {
$this->logined = false; //重置登录状态
Session::delete("admin");
Cookie::delete("keeplogin");
if ($my['token'] != $admin['token']) {
$this->logout();
return false;
}
}

View File

@ -13,22 +13,20 @@ class Admin extends Model
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $hidden = [
'password',
'salt'
];
/**
* 重置用户密码
* @author baiyouwen
*/
public function resetPassword($uid, $NewPassword)
public static function init()
{
$passwd = $this->encryptPassword($NewPassword);
$ret = $this->where(['id' => $uid])->update(['password' => $passwd]);
return $ret;
}
// 密码加密
protected function encryptPassword($password, $salt = '', $encrypt = 'md5')
{
return $encrypt($password . $salt);
self::beforeWrite(function ($row) {
$changed = $row->getChangedData();
//如果修改了用户或或密码则需要重新登录
if (isset($changed['username']) || isset($changed['password']) || isset($changed['salt'])) {
$row->token = '';
}
});
}
}

View File

@ -28,7 +28,7 @@
box-shadow: 0 0 30px rgba(0, 0, 0, 0.1);
background: rgba(255, 255, 255, 1);
border: none;
overflow: hidden;
/*overflow: hidden;*/
padding: 0;
}
@ -55,6 +55,7 @@
.login-head {
background: #899fe1;
border-radius: 3px 3px 0 0;
}
.login-form {
@ -122,12 +123,14 @@
</div>
{/if}
<!--@CaptchaEnd-->
{if $keeyloginhours>0}
<div class="form-group checkbox">
<label class="inline" for="keeplogin">
<label class="inline" for="keeplogin" data-toggle="tooltip" title="{:__('The duration of the session is %s hours', $keeyloginhours)}">
<input type="checkbox" name="keeplogin" id="keeplogin" value="1"/>
{:__('Keep login')}
</label>
</div>
{/if}
<div class="form-group">
<button type="submit" class="btn btn-success btn-lg btn-block" style="background:#708eea;">{:__('Sign in')}</button>
</div>