接下来,我们通过 Cookie Session 来完成博客管理后台的用户认证功能。
基于 Session 实现用户登录功能我们在前面的基础教程中已经演示过了,这里只需在其基础上进行改造即可。
1、准备工作
开始之前,我们先在控制器基类 AppHttpControllerController
中新增一个 $session
变量作为 Session 实例,并在控制器中初始化:
class Controller
{
...
/**
* @var Session
*/
protected $session;
public function __construct()
{
...
$this->session = $this->container->resolve('session');
}
}
另外,还需要在 app/config/app.php
中设置 Session 的有效期为 2 个小时:
'session' => [
'lifetime' => 2 * 60 * 60
]
然后在 app
目录下新建一个 helper.php
用于存放辅助函数,这里我们定义一个 redirect
函数进行重定向操作:
<?php
if (!function_exists('redirect')) {
function redirect($route, $statusCode = 301)
{
$response = new AppHttpResponse('', $statusCode, ['Location' => $route]);
$response->send();
exit();
}
}
在 composer.json
中添加如下代码从而可以自动加载这个 helper.php
文件:
"autoload": {
"files": [
"app/helper.php"
],
...
}
这样,我们在控制器发送重定向响应时就无需编写一堆重复的代码了。
2、路由和控制器
注册路由
做好以上准备工作后,在 app/routes/web.php
中注册用户登录和退出路由:
$router->register(['get', 'post'], 'login', 'AuthController@login');
$router->register('post', 'logout', 'AuthController@logout');
注:由于后台仅限管理员登录,所以不提供用户注册功能。
用户登录处理
然后创建对应的 AuthController
控制器(位于 app/http/controller
目录下),先编写用户登录相关处理逻辑:
public function login()
{
if ($this->session->has('auth_user')) {
// 用户已登录,跳转到管理后台
return redirect('/admin');
}
$siteName = $this->container->resolve('app.name');
$pageTitle = '登录页面 - ' . $siteName;
if ($this->request->getMethod() == 'GET') {
$this->view->render('admin/login.php', compact('siteName', 'pageTitle'));
} else {
$name = $this->request->get('name');
$password = $this->request->get('password');
if (empty($name) || empty($password)) {
$error = '用户名和密码不能为空';
$this->view->render('admin/login.php', compact('siteName', 'pageTitle', 'error'));
return;
}
$user = User::where('name', $name)->first();
if (empty($user)) {
// 返回到用户登录页面,并提示错误信息
$error = '对应用户不存在,请重试';
$this->view->render('admin/login.php', compact('siteName', 'pageTitle', 'error'));
return;
}
if ($user->password == md5($password)) {
// 用户登录成功
$this->session->set('auth_user', $user);
// 跳转到管理后台
return redirect('/admin');
}
// 返回到用户登录页面,并提示错误信息
$error = '用户名和密码不匹配,请重试';
$this->view->render('admin/login.php', compact('siteName', 'pageTitle', 'error', 'name'));
return;
}
}
对于 GET /login 请求,会渲染用户登录页面。
对于 POST /login 请求,会处理用户输入的登录信息,如果用户名和密码与数据库中的对应记录匹配成功,则用户认证成功,并将用户信息存储到 Session,然后跳转到后台首页;否则将错误提示信息反馈到用户登录页面。
用户退出处理
至于用户退出逻辑,则简单许多:
代码语言:javascript复制public function logout()
{
if ($this->session->has('auth_user')) {
$this->session->remove('auth_user');
$this->session->invalidate();
}
return redirect('/login');
}
从 Session 中移除认证用户信息,并跳转到登录页面。
3、视图模板
后台视图模板重构
开始编写用户登录视图模板之前,我们先对后台视图模板进行重构,因为对于后台视图而言,整体布局是一致的,头部、底部、导航、边栏代码都是可以复用的,没必要每个视图模板都重新编写一遍。
我们对之前的后台首页视图模板 resources/views/admin/index.php
按照组件进行拆分。
头部组件
resources/views/admin/header.php
对应源码:https://github.com/nonfu/master-laravel-code/blob/v1.1/practice/blog/resources/views/admin/header.php
导航组件
resources/views/admin/nav.php
对应源码:https://github.com/nonfu/master-laravel-code/blob/v1.1/practice/blog/resources/views/admin/nav.php
侧边栏组件
resources/views/admin/sidebar.php
对应源码:https://github.com/nonfu/master-laravel-code/blob/v1.1/practice/blog/resources/views/admin/sidebar.php
底部组件
resources/views/admin/footer.php
对应源码:https://github.com/nonfu/master-laravel-code/blob/v1.1/practice/blog/resources/views/admin/footer.php
主体代码
resources/views/admin/index.php
对应源码:https://github.com/nonfu/master-laravel-code/blob/v1.1/practice/blog/resources/views/admin/index.php
目前,上述视图模板中还存在很多硬编码,我们将在下篇教程中逐一将其替换成从后端读取变量进行渲染。
用户登录视图
完成上述视图模板重构后,编写用户登录页面就可以复用头部和底部组件了:
代码语言:javascript复制<?php include 'header.php';?>
<body class="bg-gradient-primary">
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">学院君管理后台</h1>
</div>
<form class="user" action="/login" method="POST">
<div class="form-group">
<input type="text" class="form-control form-control-user" id="name" name="name" aria-describedby="emailHelp" placeholder="用户名" value="<?php echo empty($name) ? '' : $name;?>">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="password" name="password" placeholder="密码">
</div>
<?php if (!empty($error)):?>
<div class="alert alert-danger" role="alert">
<?=$error?>
</div>
<?php endif;?>
<button type="submit" class="btn btn-primary btn-user btn-block">
登录
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php';?>
用户退出视图
用户退出通过一个模态框的交互来完成,对应的引用代码在导航组件 nav.php
中:
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
对应的模态框代码如下:
代码语言:javascript复制<!-- Logout Modal-->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">确定要退出?</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">点击下面的 "退出" 按钮退出管理后台</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">取消</button>
<form action="/logout" method="post">
<button class="btn btn-primary" type="submit" id="logoutBtn">退出</button>
</form>
</div>
</div>
</div>
</div>
4、测试用户认证功能
我们在 users
表中插入一条记录,然后在 DashboardController
控制器的构造函数中新增如下代码:
public function __construct()
{
parent::__construct();
if (!$this->session->has('auth_user')) {
redirect('/login');
}
}
表示如果用户没有登录的情况下访问博客后台,会重定向到登录页面。另外,在 DashboardController
的 index
方法中引入认证用户变量(用户认证后才能访问到这里),传递给视图模板进行渲染:
public function index()
{
...
$user = $this->session->get('auth_user');
$this->view->render('admin/index.php', compact('pageTitle', 'siteName', 'user'));
}
在 blog
根目录下运行 composer dump-auto
让上述代码修改导致的命名空间和自动加载调整生效:
我们在 public
目录下运行 php -S localhost:9000
启动这个博客项目,然后在浏览器中访问后台首页,由于用户尚未认证,所以会跳转到登录页面:
如果输入的用户名和密码不匹配,会提示错误信息:
登录凭证通过验证后,就可以登录成功,进入博客后台页面:
点击右上角的用户头像,下拉框会出现退出按钮:
点击退出按钮,会弹出模态框进行退出确认:
确认退出后,页面会再次重定向到登录页面,表示用户退出成功。
关于用户认证的部分,学院君就简单介绍到这里,下篇教程,我们来完善后台专辑、文章、消息的增删改查功能,从而构建博客系统前后端功能闭环。
本篇教程源码已提交到 Github 仓库:https://github.com/nonfu/master-laravel-code/tree/v1.1/practice/blog。
(全文完)