0
点赞
收藏
分享

微信扫一扫

基于egg.js框架的登录鉴权实现方案

Egg.js为企业级框架和应用而生,是阿里开源的企业级 Node.js 框架,它可以轻松创建一个项目而不用做很多繁琐的初期工作,解放生产力,更可贵的是有一套现成的规范提供给我们,适合开发者较为快速的编写后端接口。本篇使用egg.js框架,辅以egg-jwt、cookie、redis、egg-swagger-ui以及egg-sequelize技术,实现了一种登录鉴权的方案。

登录页面中,用户输入用户名、密码进行登录操作,后台查询数据库中登录信息是否一致,若不一致,则用户名密码输入错误,直接返回登录页面;若一致,则判定登录成功,通过egg-jwt插件产生token,并将信息写入redis,同时将token放入cookie中,返回给浏览器。详细流程图如下所示。

基于egg.js框架的登录鉴权实现方案_登录页面

当用户请求接口时,后台先获取传入的cookie值,若未携带cookie信息,则判定用户未登录,返回未登录状态,前端可通过该状态跳转至登录页面;若携带了cookie信息,则解密cookie值,获取到token的加密信息,通过egg-jwt密钥,解密token获取到用户登录名,鉴权中间件根据用户名以及token加密值查询redis并进行对比,若一致,则更新redis过期时间并继续进行接口请求;若不一致,则返回登录过期或异地登录。详细流程图如下所示。

基于egg.js框架的登录鉴权实现方案_用户名_02

代码实现

1、 egg-jwt及redis配置

config/config.default.ts中

config.jwt = {
       secret: 'test123456',   //自定义token的加密条件字符串,可按各自的需求填写
  };
 /** [必填]redis缓存配置 **/
    config.redis = {
        client: {
            host: '127.0.0.1',
            port: 6379,
            password: '',
            db: 0
        },
    };

在config/plugin.ts中

jwt: {
    enable: true,
    package: 'egg-jwt',
  },
  redis: {
    enable: true,
    package: 'egg-redis',
  },

登录接口代码

public async login() {
        const { ctx, app } = this;
        let name = ctx.query.userName;
        let pwd = ctx.query.pwd;
        //查询数据库用户名密码是否匹配
        let resultCount = await ctx.model.userModel.count({
            where: {
                name,
                pwd
            }
        })
        if (resultCount > 0) {
            //jwt加密产生token
            let token = app.jwt.sign({ name }, app.config.jwt.secret)
            //name:token键值对存入redis并设置过期时间
            let maxAge = 60 * 30;
            await app.redis.set(name, token, 'EX', maxAge)
            //给浏览器返回cookie 
            ctx.cookies.set("token", token, {
                // 只允许服务端访问cookie    
                httpOnly: true,
                // 对cookie进行签名,防止用户修改cookie
                signed: true,
               // 是否对cookie进行加密 
                encrypt: true
            })
            this.BaseResponse(0, 'success', '登录成功')
        }else{
            this.BaseResponse(0, 'error', '用户名密码错误')
        }
    }

退出接口代码

public async logout() {
        const { ctx, app } = this
        //解密请求头携带的cookie
        let cookie = ctx.cookies.get('token', {
            encrypt: true
        })
        //jwt根据密钥解密
        let data: any = app.jwt.verify(cookie, app.config.jwt.secret)
        let name = data.name
        //清除redis中该name对应的键值对
        await app.redis.del(name)
        this.BaseResponse(0, '', '退出')
    }

鉴权中间件代码

app/middleware/authLogin.ts

module.exports = (app) => {
        return async function authLogin(ctx, next) {
                let cookie = ctx.cookies.get('token', {
                        encrypt: true
                })
                if (cookie) {
                        let data = app.jwt.verify(cookie, app.config.jwt.secret)
                        let name = data.name
                        if (name) {
                                let res = await app.redis.get(name);
                                //redis存储的值和cookie中解密的值相同
                                if (res && res === cookie) {
                                        //继续进行接口调用
                                        await next();
                                        //刷新redis过期时间
                                        let maxAge = 60 * 30;
                                        await app.redis.expire(name, maxAge)
                                } else if (res && res !== cookie) {
                                        //接口拦截,返回未登录状态(被挤下线)
                                        ctx.body = { code: '-1', msg: '该账号在其他PC登录' }
                                } else {
                                        ctx.body = { code: '-1', msg: '已过期' }
                                }
                        } else {
                                //未登录
                                ctx.body = { code: '-1', msg: '未登录' }
                        }
                } else {
                        //未登录
                        ctx.body = { code: '-1', msg: '未登录' }
                }

        };
}

接口鉴权拦截

app/router.ts中

const authLogin = app.middleware.authLogin(app);
  router.get(baseUrl + '/ph/type/list',authLogin, controller.hyController.getAll)

效果

登录成功后携带cookie

基于egg.js框架的登录鉴权实现方案_用户名_03

Redis

基于egg.js框架的登录鉴权实现方案_用户名_04

退出后接口请求

基于egg.js框架的登录鉴权实现方案_redis_05

登录后接口请求

基于egg.js框架的登录鉴权实现方案_用户名_06


举报

相关推荐

0 条评论