预览地址:http://padmin.easys.ltd/admin/account/login
创建admin应用,controller/Account.php控制器
<?php
namespace app\admin\controller;
use app\BaseController;
use think\facade\Session;
use think\facade\Db;
use think\facade\View;
/**
* 后台账号管理
*/
class Account extends BaseController
{
// 登陆页面
public function login(){
return View::fetch('/account/login');
}
}
登陆页面视图 view/Account/login.php
<!DOCTYPE html>
<html>
<head>
<title>后台登陆</title>
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css">
<script type="text/javascript" src="/static/layui/layui.js"></script>
<style type="text/css">
.body_bg{background: url(http://zhsh520.com/hero-bg.jpg);}
.login_contain{position: absolute;left: 50%;top: 50%;width: 500px;transform: translate(-50%,-50%);}
.login_main{background: rgba(255,255,255,0.8);padding: 20px;border-radius: 5px;box-shadow: 5px 5px 20px #444}
.veriCode{cursor: pointer;border: 1px solid #f1f1f1;width: 126px;height: 35px;}
</style>
</head>
<body class="body_bg">
<div class="login_contain">
<div class="login_main">
<div class="layui-form">
<div class="layui-form-item" style="color: gray">
<h2>后台管理系统</h2>
</div>
<hr/>
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="username" placeholder="请输入用户名" value="admin">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="password" class="layui-input" name="password" placeholder="请输入密码" value="1234">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">验证码</label>
<div class="layui-input-inline">
<input type="text" class="layui-input" name="vericode" placeholder="请输入验证码">
</div>
<img src="/admin/Account/veriCode" onclick="reloadveriimg()" class="veriCode">
</div>
<div class="layui-input-block">
<input type="checkbox" name="remember" lay-skin="primary" title="记住密码">
<button class="layui-btn" onclick="dologin()">登陆</button>
</div>
</div>
</div>
</div>
</body>
</html>
这里未使用tp提供的验证码类库,我们通过原生php的GD库自己生成的,下面介绍了tp的验证码安装与使用,但是要想达到预期效果,可能还需一定配置,具体使用详见官方手册。
首先使用Composer
安装think-captcha
扩展包:
composer require topthink/think-captcha
验证码库需要开启Session才能生效。
验证码使用
扩展包内定义了一些常见用法方便使用,可以满足大部分常用场景,以下示例说明。
在模版内添加验证码的显示代码
<div>{:captcha_img()}</div>
验证码生成类
// 验证码生成
class VeriCode{
// 获取验证码配置
private static function _getCodeConfig(){
return [
// 验证码字符集
'codeStr' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
// 验证码个数
'codeCount' => 4,
// 字体大小
'fontsize' =>16,
// 验证码的宽度
'width' => 100,
// 验证码高度
'height' => 36,
// 是否有干扰点?true有,false没有
'disturbPoint' => true,
// 干扰点个数,disturbPoint开启后生效
'pointCount' => 200,
// 是否有干扰条?true有,false没有
'disturbLine' => true,
// 干扰条个数,disturbLine开启后生效
'lineCount' => 3
];
}
// 创建图片验证码
public static function create(){
// 配置
$config = self::_getCodeConfig();
//创建画布
$image = imagecreatetruecolor($config['width'],$config['height']);
//背景颜色
$bgcolor=imagecolorallocate($image,255,255,255);
imagefill($image,0,0,$bgcolor);
$captch_code = '';//存储验证码
$captchCodeArr = str_split($config['codeStr']);
//随机选取4个候选字符
for($i=0;$i<$config['codeCount'];$i++){
$fontsize = $config['fontsize'];
$fontcolor=imagecolorallocate($image,rand(0,120),rand(0,120),rand(0,120));//随机颜色
$fontcontent = $captchCodeArr[rand(0,strlen($config['codeStr'])-1)];
$captch_code.=$fontcontent;
$_x = $config['width']/$config['codeCount'];
$x=($i*(int)$_x)+rand(5,10); //随机坐标
$y=rand(5,10);
imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor); // 水平地画一行字符串
//imagefttext($im, $size, 2, $size * (0.5 + $i * 1.1), $size * 1.2, $font, Env::get('root_path') . 'public/static/fonts/COOPBL.TTF', $authnum);
}
session_start();
$_SESSION['code']=$captch_code;
//增加干扰点
if($config['disturbPoint']){
for($i=0;$i<$config['pointCount'];$i++){
$pointcolor=imagecolorallocate($image,rand(50,200),rand(50,200),rand(50,200));
imagesetpixel($image,rand(1,99),rand(1,29),$pointcolor);
}
}
//增加干扰线
if($config['disturbLine']){
for($i=0;$i<$config['lineCount'];$i++){
$linecolor=imagecolorallocate($image,rand(80,280),rand(80,220),rand(80,220));
imageline($image,rand(1,99),rand(1,29),rand(1,99),rand(1,29),$linecolor);
}
}
//输出格式
header('content-type:image/png');
imagepng($image);
//销毁图片
imagedestroy($image);
}
}
我们只需要将其放置到我们的控制器中调用即可
<?php
namespace app\admin\controller;
use app\BaseController;
use think\facade\Session;
use think\facade\Db;
use think\facade\View;
/**
* 后台账号管理
*/
class Account extends BaseController
{
// 登陆页面
public function login(){
return View::fetch('/account/login');
}
// 验证码
public function veriCode(){
VeriCode::create();
}
}
// 验证码生成……将什么复制到此处即可
页面中引入img标签,链接为生成验证码控制器方法即可
<img src="/admin/Account/veriCode" onclick="reloadveriimg()" class="veriCode">
定义reloadveriimg方法实现点击刷新验证码操作
<script type="text/javascript">
$ = layui.jquery;
// 重新加载验证码图片
function reloadveriimg(){
$('.veriCode').attr('src','/admin/Account/veriCode?rand='+Math.random());
}
</script>
前端页面采用Ajax发送后台验证信息,状态后台通过Session存储进行保持
前端登陆页面发送请求
<!DOCTYPE html>
<html>
<head>
<title>后台登陆</title>
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css">
<script type="text/javascript" src="/static/layui/layui.js"></script>
<style type="text/css">
.body_bg{background: url(http://zhsh520.com/hero-bg.jpg);}
.login_contain{position: absolute;left: 50%;top: 50%;width: 500px;transform: translate(-50%,-50%);}
.login_main{background: rgba(255,255,255,0.8);padding: 20px;border-radius: 5px;box-shadow: 5px 5px 20px #444}
.veriCode{cursor: pointer;border: 1px solid #f1f1f1;width: 126px;height: 35px;}
</style>
</head>
<body class="body_bg">
<div class="login_contain">
<div class="login_main">
<div class="layui-form">
<div class="layui-form-item" style="color: gray">
<h2>后台管理系统</h2>
</div>
<hr/>
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="username" placeholder="请输入用户名" value="admin">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="password" class="layui-input" name="password" placeholder="请输入密码" value="1234">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">验证码</label>
<div class="layui-input-inline">
<input type="text" class="layui-input" name="vericode" placeholder="请输入验证码">
</div>
<img src="/admin/Account/veriCode" onclick="reloadveriimg()" class="veriCode">
</div>
<div class="layui-input-block">
<input type="checkbox" name="remember" lay-skin="primary" title="记住密码">
<button class="layui-btn" onclick="dologin()">登陆</button>
</div>
</div>
</div>
</div>
</body>
</html>
<script type="text/javascript">
$ = layui.jquery;
// 重新加载验证码图片
function reloadveriimg(){
$('.veriCode').attr('src','/admin/Account/veriCode?rand='+Math.random());
}
// 用户名控件获取焦点
$('input[name="username"]').focus();
// 回车登录
$('input').keydown(function(e){
if(e.keyCode == 13){
dologin();
}
});
// 向后台发送登陆信息
function dologin(){
// 获取表单值并清除两端空格
var username = $.trim($('input[name="username"]').val());
var password = $.trim($('input[name="password"]').val());
var vericode = $.trim($('input[name="vericode"]').val());
var remember = $('input[name="remember"]').is(':checked')?1:0;
// 校验数据是否为空
if(username==''){
return layer.alert('用户名不能为空',{title:'错误提示',icon:2});
}
if(password==''){
return layer.alert('密码不能为空',{title:'错误提示',icon:2});
}
if(vericode==''){
return layer.alert('验证码不能为空',{title:'错误提示',icon:2});
}
$.post('/admin/account/dologin',{username,password,vericode},function(res){
if(res.code>0){
// 刷新验证码
reloadveriimg();
return layer.alert(res.msg,{title:'错误提示',icon:2});
}
layer.alert(res.msg,{title:'成功提示',icon:1});
setTimeout(function(){
window.location.href="/";
},1000)
},'json');
}
</script>
执行登陆操作的控制器方法
// 执行登陆
public function dologin(){
session_start();
// 接受登陆传递的信息
$username = input('post.username');
$password = input('post.password');
$vericode = input('post.vericode');
$remember = input('post.remember');
// password_hash 创建密码的散列
// echo $pwd = password_hash("1234",PASSWORD_DEFAULT);
// 校验是否为空
if(empty($username)){
exit(json_encode(['code'=>1,'msg'=>'用户名不能为空']));
}
if(empty($password)){
exit(json_encode(['code'=>1,'msg'=>'密码不能为空']));
}
if(empty($vericode)){
exit(json_encode(['code'=>1,'msg'=>'验证码不能为空']));
}
if(strcasecmp($_SESSION['code'],$vericode)!==0){
exit(json_encode(['code'=>1,'msg'=>'验证码不正确']));
}
// 校验用户
$admin = Db::table('admin')->where('username',$username)->find();
if(empty($admin)){
exit(json_encode(['code'=>1,'msg'=>'用户名或密码错误']));
}
// password_verify — 验证密码是否和散列值匹配
if(!password_verify($password,$admin['password'])){
exit(json_encode(['code'=>1,'msg'=>'用户名或密码错误']));
}
// 校验用户是否被禁用
if($admin['status']!=0){
exit(json_encode(['code'=>1,'msg'=>'账号已被禁用,请联系管理员']));
}
// 判断是否记住密码
if($remember==1){
// 设置用户session 7天以后过期
session_set_cookie_params('60*60*24*7');
Session::set('admin',$admin);
}else{
// 设置用户session
Session::set('admin',$admin);
}
Db::table('admin')->where('username',$username)->update(['lastlogin'=>time()]);
echo json_encode(['code'=>0,'msg'=>'登陆成功']);
// 这里通过再用exit的话,在别的控制器中获取不到session的值
// exit(json_encode(['code'=>0,'msg'=>'登陆成功']));
}