创新实训(五):用户管理之登录注册

登录注册部分主要通过 crsf_check() 函数检查 CSRF(跨站请求伪造)保护。
然后检查 $_POST 中是否存在必要的注册信息(用户名、密码、邮箱)
最后完成注册
在登录时要检测账号和对应的权限,展示相应的内容
一.项目展示:



二.登录代码介绍
1.PHP 部分
页面头部与页脚

php
<?php echoUOJPageHeader(UOJLocale::get('login')) ?>
...
<?php echoUOJPageFooter() ?>

echoUOJPageHeader 和 echoUOJPageFooter 分别输出页面的头部和尾部内容。
UOJLocale::get('login') 获取当前语言下的“登录”文本。
表单字段

php
<h2 class="page-header"><?= UOJLocale::get('login') ?></h2>
<form id="form-login" class="form-horizontal" method="post">
  <div id="div-username" class="form-group">
    <label for="input-username" class="col-sm-2 control-label"><?= UOJLocale::get('username') ?></label>
    <div class="col-sm-3">
      <input type="text" class="form-control" id="input-username" name="username" placeholder="<?= UOJLocale::get('enter your username') ?>" maxlength="20" />
      <span class="help-block" id="help-username"></span>
    </div>
  </div>
  <div id="div-password" class="form-group">
    <label for="input-password" class="col-sm-2 control-label"><?= UOJLocale::get('password') ?></label>
    <div class="col-sm-3">
      <input type="password" class="form-control" id="input-password" name="password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20" />
      <span class="help-block" id="help-password"></span>
    </div>
  </div>
  <div class="form-group">
    <div class="col-sm-offset-2 col-sm-3">
      <button type="submit" id="button-submit" class="btn btn-secondary"><?= UOJLocale::get('submit') ?></button>
    </div>
  </div>
</form>

表单包含两个输入框:一个用于用户名(input-username),另一个用于密码(input-password)。
UOJLocale::get 用于获取不同语言环境下的文本,比如“用户名”、“密码”等。
maxlength="20" 限制输入的最大字符数为20。
JavaScript 部分
表单验证函数

javascript
function validateLoginPost() {
  var ok = true;
  ok &= getFormErrorAndShowHelp('username', validateUsername);
  ok &= getFormErrorAndShowHelp('password', validatePassword);
  return ok;
}

validateLoginPost 函数用于在提交前验证输入信息是否符合要求。
getFormErrorAndShowHelp 是一个辅助函数,根据字段名调用相应的验证函数(validateUsername 或 validatePassword)并显示错误信息。
表单提交函数

javascript
function submitLoginPost() {
  if (!validateLoginPost()) {
    return false;
  }
  
  $.post('/login', {
    _token : "<?= crsf_token() ?>",
    login : '',
    username : $('#input-username').val(),
    password : md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>")
  }, function(msg) {
    if (msg == 'ok') {
      var prevUrl = document.referrer;
      if (prevUrl == '' || /.*\/login.*/.test(prevUrl) || /.*\/logout.*/.test(prevUrl) || /.*\/register.*/.test(prevUrl) || /.*\/reset-password.*/.test(prevUrl)) {
        prevUrl = '/';
      }
      window.location.href = prevUrl;
    } else if (msg == 'banned') {
      $('#div-username').addClass('has-error');
      $('#help-username').html('该用户已被封停,请联系管理员。');
    } else if (msg == 'expired') {
      $('#div-username').addClass('has-error');
      $('#help-username').html('页面会话已过期。');
    } else {
      $('#div-username').addClass('has-error');
      $('#help-username').html('用户名或密码错误。');
      $('#div-password').addClass('has-error');
      $('#help-password').html('用户名或密码错误。<a href="/forgot-password">忘记密码?</a>');
    }
  });
  return true;
}

submitLoginPost 在通过验证后发送POST请求到 /login。
使用 md5 函数将密码加密,并添加客户端盐(salt),确保传输过程中的安全性。
根据服务器返回的消息(msg),处理不同的响应结果:
'ok':登录成功,跳转到先前页面(若无先前页面则跳转到主页)。
'banned':用户被封停,显示错误信息。
'expired':会话过期,显示错误信息。
其他情况:用户名或密码错误,显示错误信息及“忘记密码”链接。
表单提交事件处理

javascript
$(document).ready(function() {
$('#form-login').submit(function(e) {
e.preventDefault();
submitLoginPost();
});
});
使用 jQuery 的 $(document).ready 确保DOM完全加载后再绑定事件。
阻止默认表单提交行为,调用 submitLoginPost 函数处理登录逻辑。
三.注册代码介绍:
函数 handleRegisterPost():

php
function handleRegisterPost() {
    if (!crsf_check()) {
        return '页面已过期';
    }
    if (!isset($_POST['username'])) {
        return "无效表单";
    }
    if (!isset($_POST['password'])) {
        return "无效表单";
    }
    if (!isset($_POST['email'])) {
        return "无效表单";
    }
    $username = $_POST['username'];
    $password = $_POST['password'];
    $email = $_POST['email'];
    if (!validateUsername($username)) {
        return "失败:无效用户名。";
    }
    if (queryUser($username)) {
        return "失败:用户名已存在。";
    }
    if (!validatePassword($password)) {
        return "失败:无效密码。";
    }
    if (!validateEmail($email)) {
        return "失败:无效电子邮箱。";
    }
    
    $password = getPasswordToStore($password, $username);
    
    $esc_email = DB::escape($email);
    
    $svn_pw = uojRandString(10);
    if (!DB::selectCount("SELECT COUNT(*) FROM user_info"))
        DB::query("insert into user_info (username, email, password, svn_password, register_time, usergroup) values ('$username', '$esc_email', '$password', '$svn_pw', now(), 'S')");
    else
        DB::query("insert into user_info (username, email, password, svn_password, register_time) values ('$username', '$esc_email', '$password', '$svn_pw', now())");
    
    return "欢迎你!" . $username . ",你已成功注册。";
}

功能:
首先通过 crsf_check() 函数检查 CSRF(跨站请求伪造)保护。
然后检查 $_POST 中是否存在必要的注册信息(用户名、密码、邮箱),如果不存在则返回 "无效表单"。
使用 validateUsername($username) 验证用户名的有效性,如果无效则返回 "失败:无效用户名。"
使用 queryUser($username) 查询数据库中是否已存在该用户名,如果存在则返回 "失败:用户名已存在。"
使用 validatePassword($password) 和 validateEmail($email) 分别验证密码和邮箱的有效性。
如果所有验证通过,则调用 getPasswordToStore($password, $username) 函数准备存储的密码。
使用 DB::escape($email) 函数对邮箱进行数据库安全转义。
生成一个随机的 svn_password,然后执行 SQL 插入语句将用户信息插入 user_info 表中。
最后返回 "欢迎你!" 加上用户名的消息,表示注册成功。
2.注册处理逻辑:

php
if (isset($_POST['register'])) {
    echo handleRegisterPost();
    die();
}

当前端提交注册表单时(通过 $_POST['register']),调用 handleRegisterPost() 处理注册,并输出处理结果后终止脚本执行。
3.检查用户名是否可用:

php
elseif (isset($_POST['check_username'])) {
    $username = $_POST['username'];
    if (validateUsername($username) && !queryUser($username)) {
        echo '{"ok" : true}';
    } else {
        echo '{"ok" : false}';
    }
    die();
}

当前端通过 AJAX 发送 check_username 请求时,验证用户名是否可用。
如果 validateUsername($username) 验证通过且 queryUser($username) 返回 false(即用户名不存在),返回 {"ok" : true}。
否则返回 {"ok" : false}。
4.主体部分:
前端部分 (HTML和JavaScript)
HTML表单部分:

包含了用户输入邮箱、用户名、密码和确认密码的表单。
使用Bootstrap样式,通过form-horizontal类实现水平布局的表单。
JavaScript函数和事件绑定:

checkUsernameNotInUse():该函数使用AJAX向服务器发送请求,检查用户名是否已被使用。如果用户名已存在,返回false,否则返回true。
validateRegisterPost():验证注册表单数据的有效性。
调用validateEmail()验证邮箱格式。
调用validateUsername()验证用户名格式,并通过checkUsernameNotInUse()检查用户名是否可用。
调用validateSettingPassword()验证密码格式。
如果任何一项验证失败,返回false;否则返回true。
submitRegisterPost():提交注册表单的主函数。
首先调用validateRegisterPost()验证表单数据。
如果验证通过,使用$.post方法发送POST请求给服务器的/register路径。
发送的数据包括用户名、邮箱和经过加密的密码(使用MD5和客户端盐)。
根据服务器返回的消息,如果注册成功,显示成功对话框并跳转到之前的页面;如果失败,显示失败对话框。
事件绑定:

使用jQuery在文档准备就绪时绑定表单的提交事件。当用户点击注册按钮时,调用submitRegisterPost()函数进行处理。
后端部分 (PHP)
PHP标记:

使用包裹PHP代码,动态生成页面内容和处理表单提交。
服务器端处理:

接收POST请求,根据请求内容进行注册处理。
使用crsf_token()生成和验证CSRF令牌,确保请求的安全性。
处理注册逻辑,包括用户名是否重复、密码加密、成功或失败时返回不同的消息。

<?php
	$REQUIRE_LIB['md5'] = '';
	$REQUIRE_LIB['dialog'] = '';
?>
<?php echoUOJPageHeader(UOJLocale::get('register')) ?>
<h2 class="page-header"><?= UOJLocale::get('register') ?></h2>
<form id="form-register" class="form-horizontal">
	<div id="div-email" class="form-group">
		<label for="input-email" class="col-sm-2 control-label"><?= UOJLocale::get('email') ?></label>
		<div class="col-sm-3">
			<input type="email" class="form-control" id="input-email" name="email" placeholder="<?= UOJLocale::get('enter your email') ?>" maxlength="50" />
			<span class="help-block" id="help-email"></span>
		</div>
	</div>
	<div id="div-username" class="form-group">
		<label for="input-username" class="col-sm-2 control-label"><?= UOJLocale::get('username') ?></label>
		<div class="col-sm-3">
			<input type="text" class="form-control" id="input-username" name="username" placeholder="<?= UOJLocale::get('enter your username') ?>" maxlength="20" />
			<span class="help-block" id="help-username"></span>
		</div>
	</div>
	<div id="div-password" class="form-group">
		<label for="input-password" class="col-sm-2 control-label"><?= UOJLocale::get('password') ?></label>
		<div class="col-sm-3">
			<input type="password" class="form-control" id="input-password" name="password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20" />
			<input type="password" class="form-control top-buffer-sm" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your password') ?>" maxlength="20" />
			<span class="help-block" id="help-password"></span>
		</div>
	</div>
	<div class="form-group">
		<div class="col-sm-offset-2 col-sm-3">
			<button type="submit" id="button-submit" class="btn btn-secondary"><?= UOJLocale::get('submit') ?></button>
		</div>
	</div>
</form>

<script type="text/javascript">
function checkUsernameNotInUse() {
	var ok = false;
	$.ajax({
		url : '/register',
		type : 'POST',
		dataType : 'json',
		async : false,
		
		data : {
			check_username : '',
			username : $('#input-username').val()
		},
		success : function(data) {
			ok = data.ok;
		},
		error :	function(XMLHttpRequest, textStatus, errorThrown) {
			alert(XMLHttpRequest.responseText);
			ok = false;
		}
	});
	return ok;
}
function validateRegisterPost() {
	var ok = true;
	ok &= getFormErrorAndShowHelp('email', validateEmail);
	ok &= getFormErrorAndShowHelp('username', function(str) {
		var err = validateUsername(str);
		if (err)
			return err;
		if (!checkUsernameNotInUse())
			return '该用户名已被人使用了。';
		return '';
	})
	ok &= getFormErrorAndShowHelp('password', validateSettingPassword);
	return ok;
}

function submitRegisterPost() {
	if (!validateRegisterPost()) {
		return;
	}
	
	$.post('/register', {
		_token : "<?= crsf_token() ?>",
		register : '',
		username : $('#input-username').val(),
		email		: $('#input-email').val(),
		password : md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>")
	}, function(msg) {
		if (/^欢迎你!/.test(msg)) {
			BootstrapDialog.show({
				title	 : '注册成功',
				message : msg,
				type		: BootstrapDialog.TYPE_SUCCESS,
				buttons: [{
					label: '好的',
					action: function(dialog) {
						dialog.close();
					}
				}],
				onhidden : function(dialog) {
					var prevUrl = document.referrer;
					if (!prevUrl) {
						prevUrl = '/';
					};
					window.location.href = prevUrl;
				}
			});
		} else {
			BootstrapDialog.show({
				title	 : '注册失败',
				message : msg,
				type		: BootstrapDialog.TYPE_DANGER,
				buttons: [{
					label: '好的',
					action: function(dialog) {
						dialog.close();
					}
				}],
			});
		}
	});
}
$(document).ready(function() {
	$('#form-register').submit(function(e) {
		submitRegisterPost();
		return false;
	});
});
</script>
<?php echoUOJPageFooter() ?>

posted @   ighshssjjsjs  阅读(16)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示