eggjs中的passport实践

eggjs是阿里开源的一个针对企业级应用的nodejs框架,最近在学习eggjs中的passport,走了一些弯路,写一点心得,使用local策略实现本地登录。

安装相关的依赖

npm i --save egg-passport egg-passport-local

开启插件

config\plugin.js

exports.passport = {
  enable: true,
  package: 'egg-passport',
};

exports.passportLocal = {
  enable: true,
  package: 'egg-passport-local',
};

配置用户名密码字段

config\config.default.js

  config.passportLocal = {
    usernameField: 'username',
    passwordField: 'password',
  };

配置验证用户以及序列化与反序列化

app.js中,添加逻辑

  app.passport.verify(async (ctx, user) => {
    // 查找数据库,并验证密码是否正确
    /*
    const User = ctx.model.User;
    let foundUser = await User.findOne({ username: user.username });
    if(!foundUser || !foundUser.encryptPassword(user.password)) return false;
    return foundUser;
    */
    return user;
  });

  // 序列化与反序列化,序列化存储到session中只保存用户id
  app.passport.serializeUser(async (ctx, user) => {
    // return pick(user, ['id', 'name', 'username', 'email']);
    return user;
  });

  app.passport.deserializeUser(async (ctx, user) => {
    return user;
  });

创建控制路由

controller文件夹中,创建home.js,添加控制路由

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

class HomeController extends Controller {
  async index() {
    const ctx = this.ctx;
    ctx.body = `
      <div>
        <h2>${ctx.path}</h2>
        <a href="/admin">admin</a>
      </div>
    `;
  }

  async admin() {
    const { ctx } = this;
    if (ctx.isAuthenticated()) {
      console.log('ctx.user', ctx.user);
      // show user info
      ctx.body = `
        <div>
          <h3>You login</h3>
          <a href="/logout">Logout</a>
        </div>
      `;
      
    } else {
      // redirect to origin url by ctx.session.returnTo
      ctx.session.returnTo = ctx.path;
      // await ctx.render('login.html');
      ctx.redirect('/login');
    }
  }

  async login() {
    await this.ctx.render('login.html');
  }

  async logout() {
    const ctx = this.ctx;
    ctx.logout();
    ctx.redirect(ctx.get('referer') || '/');
  }

  async register() {
    await this.ctx.render('register.html');
  }

  async doRegister() {
    const ctx = this.ctx;
    const User = ctx.model.User;
    console.log('model is ', User);
    const requestBody = ctx.request.body;
    const user = new User(requestBody);
    user.provider = 'local';
    const result = await user.save();
    console.log('result is ', result);
    ctx.redirect('/');
  }

  async loginCallback() {
    let { ctx } = this;
    if (ctx.isAuthenticated()) {
      ctx.body = {
        code: 0,
        data: ctx.user,
        msg: '',
      };
    } else {
      ctx.body = {
        code: -1, 
        data: null,
        msg: '用户名或密码错误'
      }
    }

  }
}

module.exports = HomeController;

配置路由

router.js中,配置

module.exports = app => {
  const { router, controller } = app;

  let { home } = controller;

  router.get('/', home.index);
  router.get('/admin', home.admin);
  router.get('/logout', home.logout);
  router.get('/login', home.login);

  const localStrategy = app.passport.authenticate('local', {successRedirect: '/loginCallback', failureRedirect: '/loginCallback'});
  router.post('/passport/local', localStrategy);
  router.post('/passport/local', home.localPassport);
  router.get('/loginCallback', home.loginCallback);
  
  router.get('/register', home.register);
  router.post('/register', home.doRegister);
};

在这里,localStrategy的定义中,添加了 successRedirectfailureRedirect并且指向了同一个路由,在loginCallback中,判断是否登录,并返回对应的json数据,这种是为了处理ajax请求的情况。

app.passport.authenticate('local', {successRedirect: '/loginCallback', failureRedirect: '/loginCallback'})

前端代码

app/view
login.html

<html>
  <head>
    <title>Login</title>
    <script type="text/javascript" src="/public/lib/js.cookie.js"></script>
    <script type="text/javascript" src="/public/lib/jquery-1.12.4.min.js"></script>
    <script>
    $(function(){
    // 对于所有的ajax请求,请求头添加cookie标识
    var csrftoken = Cookies.get('csrfToken');

    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader('x-csrf-token', csrftoken);
          }
        },
      });
    });
    </script>
  </head>
  <body>
    <form method="post" id="loginForm">
      <input type="text" name="username" placeholder="用户"/>
      <input type="password" name="password" placeholder="密码"/>
      <input type="submit" value="提交"/>
    </form>
    <div>
      没有账号?<a href="/register">注册</a>
    </div>
  </body>
  <script type="text/javascript">
    $('#loginForm').on('submit', function(e) {
      e.preventDefault();
      let username = this.username.value.trim();
      let password = this.password.value.trim();
      $.ajax({
        url: '/passport/local',
        method: 'post',
        data: {
          username: username,
          password: password
        }
      }).then((res, statusCode, xx) => {
        console.log('res ', res, statusCode, xx);
        console.log()
      }, error => {
        if(error.status === 401) {
          alert("账号或密码错误");
        }
        console.warn('error ', error);
      })
    });
  </script>
</html>

Done!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容