# 一、配置session

管理员登录信息我们采用session存储,先配置一下session
config/config.default.js

//配置session
  config.session = {
    //在有些场景下,我们希望用户如果长时间都在访问我们的站点
    //则延长他们的session有效期,不让用户退出状态
    renew:true,
    //key代表存储session的cookie键值对的
    key:'EGG_SESS',
    //最长保留时间(毫秒)
    maxAge:24*3600*1000*30,//30天
    //设置键值对是否可以被js访问,默认true,不容许被js访问
    httpOnly:true,
    //加密
    encrypt:true,
  };

# 二、定义控制器和路由

  1. 定义一个控制器将后台首页、管理员登录退出等功能写在里面
    新建控制器 app/controller/admin/home.js
'use strict';

// 哈希函数加密
const crypto = require('node:crypto');

const Controller = require('egg').Controller;

class HomeController extends Controller {
    //管理员登录页面---后台登录页面
    async login() {
        let { ctx } = this;
        await ctx.render('admin/home/login.html');
    }

    //管理员登录逻辑
    async loginevent() {
        let { ctx, app } = this;
        //参数验证
        this.ctx.validate({
            username: {
                type: 'string',  //参数类型
                required: true, //是否必须
                // defValue: '', 
                desc: '管理员账号' //字段含义
            },
            password: {
                type: 'string',
                required: true,
                // defValue: '', 
                desc: '管理员密码'
            },
        });
        // 拿参数
        let { username, password } = ctx.request.body;
        // 判断管理员是否存在
        let manager = await ctx.model.Manager.findOne({
            where: {
                username: username
            }
        });
        // 不存在则抛出异常
        if (!manager) {
            ctx.throw(400, '该管理员不存在或者被禁用了');
        }
        // 存在则验证密码
        await this.checkPassword(password, manager.password);
        //存储在session中,定义session中的一个属性auth存储登录信息
        ctx.session.auth = manager;
        return ctx.apiSuccess('ok');
    }

    // 验证密码
    async checkPassword(password, hash_password) {
        // 先对需要验证的密码进行加密
        const hmac = crypto.createHash("sha256", this.app.config.crypto.secret);
        hmac.update(password);
        password = hmac.digest("hex");
        let res = password === hash_password;
        if (!res) {
            this.ctx.throw(400, '密码错误');
        }
        return true;
    }

}

module.exports = HomeController;

  1. 定义路由
    app/router/admin.js
 // 管理员登录界面
 router.get('/admin/login', controller.admin.home.login);
 //管理员登录逻辑
 router.post('/admin/loginevent', controller.admin.home.loginevent);
  1. 登录页面
    app/view/admin/home/login.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
        <title>后台管理中心 - 登录</title>
		
		<!-- Favicon -->
        <link rel="shortcut icon" type="image/x-icon" href="/public/assets/img/favicon.png">

		<!-- Bootstrap CSS -->
        <link rel="stylesheet" href="http://cdn.bootstrapmb.com/bootstrap/4.3.1/css/bootstrap.min.css">
		
		<!-- Fontawesome CSS -->
        <link rel="stylesheet" href="/public/assets/css/font-awesome.min.css">
		
		<!-- Main CSS -->
        <link rel="stylesheet" href="/public/assets/css/style.css">
		
		<!--[if lt IE 9]>
			<script src="/public/assets/js/html5shiv.min.js"></script>
			<script src="/public/assets/js/respond.min.js"></script>
		<![endif]-->

        <!-- jQuery -->
        <script src="/public/assets/js/jquery-3.2.1.min.js"></script>
		
		<!-- Bootstrap Core JS -->
        <script src="/public/assets/js/popper.min.js"></script>
        <script src="http://cdn.bootstrapmb.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
		
		<!-- Custom JS -->
		<script src="/public/assets/js/script.js"></script>

        <script src="/public/assets/js/vue.2.7.0.min.js"></script>
		<script src="/public/assets/js/vue.component.js"></script>
    </head>
    <body>
	
		<!-- Main Wrapper -->
        <div class="main-wrapper login-body" id="vueapp">

            {# 消息提示组件 #}
            <toast ref="toast"></toast>
			{# 弹出确认框组件 #}
            <confirm ref="confirm"></confirm>


            <div class="login-wrapper">
            	<div class="container">
                	<div class="loginbox">
                    	<div class="login-left">
							<!-- <img class="img-fluid" src="/public/assets/img/logo.png" alt="Logo">  -->
                            <div class="img-fluid">
								<h3 class="text-white">后台管理中心入口</h3>
							</div>
                        </div>
                        <div class="login-right">
							<div class="login-right-wrap">
								<h1>登 录</h1>
								<p class="account-subtitle">后台管理中心欢迎您</p>
								
								<!-- Form -->
								<form >
									<div class="form-group">
										<input class="form-control" type="text" 
										placeholder="输入用户名..." v-model="form.username">
									</div>
									<div class="form-group">
										<input class="form-control" type="text" 
                                       placeholder="输入密码..." v-model="form.password">
									</div>
									<div class="form-group">
										<button class="btn btn-primary btn-block" type="submit" 
										@click.stop.prevent="submit">登 录</button>
									</div>
								</form>
								  
							</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
		<!-- /Main Wrapper -->
		
		<script>
            var Vueapp = new Vue({
				el:'#vueapp',
                data(){
                    return {
                        form:{
                            username:'',
                            password:'',
                        }
                    }
                },
                methods:{
                    submit(){
                        console.log('执行登录',this.form);
                    }
                }
			});
        </script>
		
    </body>
</html>

# 三、实现管理员登录功能

app/view/admin/home/login.html

...
<script>
    var Vueapp = new Vue({
        el:'#vueapp',
        data(){
            return {
                form:{
                    username:'',
                    password:'',
                }
            }
        },
        methods: {
            submit(){
                console.log('提交登录',this.form);
                $.ajax({
                    type: 'POST', 
                    url: "/admin/loginevent?_csrf={{ctx.csrf|safe}}",
                    contentType:'application/json;charset=UTF-8;',
                    data:JSON.stringify(this.form),
                    success: function (response, stutas, xhr) {
                        console.log(response)
                        Vueapp.$refs.toast.show({
                            msg:"登录成功",
                            type:'success',
                            delay:1000,
                            success:function(){
                                // 跳转到某个页面
                                window.location.href = "/admin/manager/index";
                            }
                        });
                    },
                    error:function(e){
                        console.log(e)
                        Vueapp.$refs.toast.show({
                            msg:e.responseJSON.data,
                            type:'danger',
                            delay:3000
                        });
                    }
                });
            }
        }
    });
</script>
</body>
</html>

# 四、权限验证,即后台所有栏目需要管理员登录才能查看

# ① 需要新建一个中间件做权限验证,app/middleware/admin_auth.js

module.exports = (option, app)=>{
    return async function adminAuth(ctx,next){
       //拿到管理员的登录信息
       //  console.log(ctx.session.auth);
       if(!ctx.session.auth){
          ctx.toast('请先登录!','danger');
          return ctx.redirect('/admin/login');
       }

      await next();

       if(ctx.status === 404){
          await ctx.pageFail('页面不存在');
       }
    }
}

# ② 中间件配置 config/config.default.js

...
config.middleware = ['errorHandler','adminAuth'];
config.adminAuth = {
    ignore:[
      "/admin/login",
      "/admin/loginevent",
    ],
  };
...

# ③ 控制器管理员登录方法完善 app/controller/admin/home.js

  //管理员登录页面---后台登录页面
  async login() {
    // const { ctx,app } = this;
    let toast = this.ctx.cookies.get('toast',{encrypt: true});
    toast = toast ? JSON.parse(toast) : null;
    await this.ctx.render('admin/home/login.html',{
        toast
    });
  }

# ④ 登录页面提示请先登录 app/view/admin/home/login.html

...
<script>
var Vueapp = new Vue({
    ...
    //页面加载完毕
    mounted(){
        var toast = "{{toast.msg}}";
        if(this.$refs.toast && toast){
            this.$refs.toast.show({
                msg:'{{toast.msg}}',
                type:'{{toast.type}}',
                delay:1500
            });
        }
    },
    ...
});
</script>

# 五、管理员退出登录

# ① 退出登录方法 app/controller/admin/home.js

    //管理员退出登录
    async logout(){
        let {ctx} = this;
        //清除session
        ctx.session.auth = null;
        ctx.toast('退出登录成功','success');
        ctx.redirect('/admin/login');
    }

# ② 定义路由 app/router/admin.js

    //管理员退出登录
    router.get('/admin/logout', controller.admin.home.logout);

# ③ 模版页面退出 app/view/admin/layout/_header.html

<a class="dropdown-item" href="/admin/logout">退出登录</a>
更新时间: 2024年3月7日星期四下午5点46分