Files
mrbs-equbao-2026/mrbs_auth.inc
T
人事系统开发 1ba6efd8ed MRBS 1.12.2 等保2.0二级整改完整提交
包含:登录失败锁定、90天密码有效期、30分钟会话超时、
强制改密、登录审计日志、屏幕水印、企业背景图、
备案信息固定底部、favicon、JS空集合保护、
会话过期体验优化(403 JSON)、display_errors 关闭、
固定 key 根治 Integrity check failed 等全部改动

注意:config.inc.php/.htaccess/.user.ini 含敏感信息,
通过 .gitignore 排除,勿推送到公开仓库。
2026-09-09 16:55:02 +08:00

492 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace MRBS;
use MRBS\Auth\AuthFactory;
use MRBS\Session\Session;
use MRBS\Session\SessionFactory;
// Convenience wrapper function to provide access to an Auth object
function auth()
{
global $auth;
static $auth_obj = null;
if (is_null($auth_obj))
{
$auth_obj = AuthFactory::create($auth['type']);
}
return $auth_obj;
}
// Convenience wrapper function to provide access to a Session object
function session() : Session
{
global $auth;
static $session_obj = null;
if (is_null($session_obj))
{
$session_obj = SessionFactory::create($auth['session']);
}
return $session_obj;
}
// Checks if a page is open to users, using the config variables
// $auth['only_admin_can_book'] and $auth['only_admin_can_book_before']
function booking_level() : int
{
global $auth;
if ($auth['allow_anonymous_booking'])
{
return 0;
}
if ($auth['only_admin_can_book'])
{
return 2;
}
elseif ($auth['only_admin_can_book_before'])
{
$go_live = strtotime($auth['only_admin_can_book_before']);
if ($go_live === false)
{
$message = "Could not calculate time from '" . $auth['only_admin_can_book_before'] . "'.";
trigger_error($message);
return 2;
}
else
{
return (time() >= $go_live) ? 1 : 2;
}
}
return 1;
}
// Gets the minimum user level required to access a page
function get_page_level($page)
{
global $auth, $max_level;
// If you're resetting your password you won't be logged in and $auth['deny_public_access']
// should not apply. (change_password.php 同样放行:页面自身强制要求已登录,未登录会引导登录)
if (in_array($page, array('reset_password.php', 'reset_password_handler.php', 'change_password.php')))
{
return 0;
}
// Otherwise ...
switch ($page)
{
// These pages are open to the public by default as they only contain
// read features.
case 'help.php':
case 'index.php':
$result = 0;
break;
// These pages reveal usernames, which could be of assistance to someone trying to
// break into the system, so users are required to be logged in before viewing them.
case 'search.php':
$result = 1;
break;
case 'view_entry.php':
$result = ($auth['allow_anonymous_booking']) ? 0 : 1;
break;
// These pages are set to have a minimum access level of 1 as ordinary users
// should be able to access them because they will have read access and in some
// cases write access for their own entries. Where necessary further checks are
// made within the page to prevent ordinary users gaining access to admin features.
case 'admin.php':
case 'approve_entry_handler.php': // Ordinary users are allowed to remind admins
case 'edit_message.php': // Booking admins can edit messages
case 'edit_message_handler.php': // Booking admins can edit messages
case 'edit_room.php': // Ordinary users can view room details
case 'edit_users.php': // Ordinary users can edit their own details
case 'pending.php': // Ordinary users can view their own entries
case 'registration_handler.php': // Ordinary users can register for an event
case 'usernames.php': // Ajax page for getting a list of users (booking admins can use this)
$result = 1;
break;
// These pages allow users to create and delete entries
case 'check_slot.php': // Ajax page used by edit_entry.php
case 'del_entry.php':
case 'edit_entry.php':
case 'edit_entry_handler.php':
return booking_level();
break;
// Everything else is for admins only
default:
$result = (isset($max_level)) ? $max_level : 2;
break;
}
if ($auth['deny_public_access'])
{
$result = max($result, 1);
}
// Can always access index.php when in kiosk mode
if ($page == 'index.php' && is_kiosk_mode())
{
$result = 0;
}
return $result;
}
/* getAuthorised($level)
*
* Check to see if the current user has a certain level of rights
*
* $level - The access level required
* $returl - The URL to return to eventually
*
* Returns:
* false - The user does not have the required access
* true - The user has the required access
*/
function getAuthorised($level, $returl) : bool
{
// If the minimum level is zero (or not set) then they are
// authorised, whoever they are
if (empty($level))
{
return true;
}
// Otherwise we need to check who they are
$mrbs_user = session()->getCurrentUser();
if(!isset($mrbs_user))
{
// Ask them to authenticate, if the session scheme supports it
if (method_exists(session(), 'authGet'))
{
session()->authGet(null, $returl);
}
return false;
}
return ($mrbs_user->level >= $level);
}
/* checkAuthorised()
*
* Checks to see that a user is authorised to access a page.
* If they are not, then shows an "Access Denied" message and exits.
*
*/
function checkAuthorised($page, $just_check=false)
{
global $view, $view_all, $year, $month, $day, $area, $room;
global $returl;
// Get the minimum authorisation level for this page
$required_level = get_page_level($page);
if ($just_check)
{
if ($required_level == 0)
{
return true;
}
$mrbs_user = session()->getCurrentUser();
return (isset($mrbs_user) && ($mrbs_user->level >= $required_level));
}
// Check that the user has this level
if (getAuthorised($required_level, $returl))
{
return true;
}
// If we don't know the right date then use today's
if (!isset($day) or !isset($month) or !isset($year))
{
$day = date('d');
$month = date('m');
$year = date('Y');
}
if (empty($area))
{
$area = get_default_area();
}
showAccessDenied($view, $view_all, $year, $month, $day, $area, isset($room) ? $room : null);
exit();
}
/* getWritable($creator, $room)
*
* Determines if the current user is able to modify an entry
*
* $creator - The creator of the entry
* $rooms - The id(s) of the room(s) that the entries are in. Can
* be a scalar or an array.
* $all - Whether to check that the creator has write access
* for all ($all=true) or just some ($all=false) of the
* rooms.
*
* Returns:
* false - The user does not have the required access
* true - The user has the required access
*/
function getWritable($creator, $rooms=null, $all=true) : bool
{
if (is_array($rooms) && (count($rooms) > 0))
{
if ($all)
{
// We want the user to have write access for all the rooms,
// so if for any one room they are not, then return false.
foreach ($rooms as $room)
{
if (!getWritable($creator, $room))
{
return false;
}
}
return true;
}
else
{
// We want the user to have write access for at least one room,
// so if there are no rooms for which they do, then return false.
foreach ($rooms as $room)
{
if (getWritable($creator, $room))
{
return true;
}
}
return false;
}
}
if (is_null($rooms) && !$all)
{
// Not yet supported. Could support it but need to decide what $rooms=null means.
// Does it mean all rooms in the system or just all rooms in the current area?
throw new \Exception('$rooms===null and $all===false not yet supported.');
}
// You can't make bookings in rooms which are invisible
if (!is_visible($rooms))
{
return false;
}
// Always allowed to modify your own stuff
$mrbs_user = session()->getCurrentUser();
if (isset($mrbs_user) && isset($creator) && (compare_usernames($creator, $mrbs_user->username) === 0))
{
return true;
}
// Otherwise you have to be a (booking) admin for this room
if (is_book_admin($rooms))
{
return true;
}
// Unauthorised access
return false;
}
/* showAccessDenied()
*
* Displays an appropriate message when access has been denied
*
* Returns: Nothing
*/
function showAccessDenied($view=null, $view_all=null, $year=null, $month=null, $day=null, $area=null, $room=null)
{
global $server;
$context = array(
'view' => $view,
'view_all' => $view_all,
'year' => $year,
'month' => $month,
'day' => $day,
'area' => $area,
'room' => isset($room) ? $room : null
);
print_header($context);
// Wrap the contents in a <div> to help with styling. Not a very nice solution, but anyway.
echo "<div>\n";
echo "<h1>" . get_vocab("accessdenied") . "</h1>\n";
echo "<p>" . get_vocab("norights") . "</p>\n";
$referrer = session()->getReferrer();
if (isset($referrer))
{
echo "<p>\n";
echo "<a href=\"" . escape_html($referrer) . "\">\n" . get_vocab("returnprev") . "</a>\n";
echo "</p>\n";
}
echo "</div>\n";
// Print footer and exit
print_footer(true);
}
// Checks whether the current user has admin rights
function is_admin() : bool
{
global $max_level;
$mrbs_user = session()->getCurrentUser();
$required_level = (isset($max_level) ? $max_level : 2);
return (isset($mrbs_user) && ($mrbs_user->level >= $required_level));
}
// Checks whether the current user has booking administration rights
// for $rooms - ie is allowed to modify and delete other people's bookings
// and to approve bookings.
//
// $rooms can be either a single scalar value or an array of room ids. The default
// value for $rooms is all rooms. (At the moment $room is ignored, but is passed here
// so that later MRBS can be enhanced to provide fine-grained permissions.)
//
// $all specifies whether the user must be a booking for all $rooms, or just some of
// them, ie at least one.
//
// Returns: TRUE if the user is allowed has booking admin rights for
// the room(s); otherwise FALSE
function is_book_admin($rooms=null, $all=true) : bool
{
global $min_booking_admin_level;
if (is_array($rooms) && (count($rooms) > 0))
{
if ($all)
{
// We want the user to be a booking admin for all the rooms,
// so if for any one room they are not, then return false.
foreach ($rooms as $room)
{
if (!is_book_admin($room))
{
return false;
}
}
return true;
}
else
{
// We want the user to be a booking admin for at least one room,
// so if there are no rooms for which they are, then return false.
foreach ($rooms as $room)
{
if (is_book_admin($room))
{
return true;
}
}
return false;
}
}
if (is_null($rooms) && !$all)
{
// Not yet supported. Could support it but need to decide what $rooms=null means.
// Does it mean all rooms in the system or just all rooms in the current area?
throw new \Exception('$rooms===null and $all===false not yet supported.');
}
$mrbs_user = session()->getCurrentUser();
return (isset($mrbs_user) && ($mrbs_user->level >= $min_booking_admin_level));
}
// Checks whether the current user has user editing rights
function is_user_admin() : bool
{
global $min_user_editing_level;
$mrbs_user = session()->getCurrentUser();
return (isset($mrbs_user) && ($mrbs_user->level >= $min_user_editing_level));
}
// Checks whether a room is visible to the current user
// Doesn't do anything at the moment, but allows for customisation or future development
function is_visible($room) : bool
{
return true;
}
// Checks whether a user is allowed to register other users for events
function can_register_others($room_id=null) : bool
{
global $auth;
$mrbs_user = session()->getCurrentUser();
if (!isset($mrbs_user))
{
return false;
}
return $auth['users_can_register_others'] || is_book_admin($room_id);
}
// Checks whether the current user can see others' email addresses
function can_see_email_addresses() : bool
{
global $auth, $is_private_field;
// Admins can see everything
if (is_admin())
{
return true;
}
$mrbs_user = session()->getCurrentUser();
// Don't expose email addresses to the public
if (!isset($mrbs_user))
{
return false;
}
// MRBS must be configured for logged-in users to see others' details
if ($auth['only_admin_can_see_other_users'])
{
return false;
}
// Otherwise the email field in the users table must not be private
return (!auth()->canCreateUsers() || empty($is_private_field['users.email']));
}