koa2中使用的是 koa-passport 这个包。
本地验证用的是 passport-local这个策略
npm install -S koa-passport
因为passport使用之前要定义策略及序列化与反序列化操作,所以把 passport 的配置及策略写到一个文件passport.js。
const passport = require('koa-passport') // const UserModel = require('../dbs/modules/users') import UserModel from '../dbs/modules/users' const LocalStrategy = require('passport-local').Strategy import cryptoJS from "crypto-js"; import Crypto from "../utils/crypto"; passport.use(new LocalStrategy( /** * @param username 用户输入的用户名 * @param password 用户输入的密码 * @param done 验证验证完成后的回调函数,由passport调用 */ async function (username, password, done) { let result = await UserModel.findOne({ username }) if (result && result != null) { if (Crypto.get(unescape(result.password)) === Crypto.get(unescape(password))) { return done(null, doPassword(result)) } else { return done(null, false, '密码错误') } } else { return done(null, false, '用户不存在') } } )) // serializeUser 在用户登录验证成功以后将会把用户的数据存储到 session 中 passport.serializeUser(function (user, done) { done(null, user) }) passport.deserializeUser(function (user, done) { return done(null, user) }) //隐藏密码,相当于是去掉密码的用户信息保存在session里 function doPassword(user) { if (user) { user.password = '' return user } else { return null } } module.exports = passport
入口载入
const passport = require('./utils/passport')
并在适当位置(看下边 app.js)使用passport中间件
app.use(passport.initialize()) app.use(passport.session())
passport 中间件需要用到 session ()所以,你的app.js入口文件类似这样
// const Koa = require('koa') import Koa from 'koa' const consola = require('consola') const { Nuxt, Builder } = require('nuxt') const mongoose = require('mongoose'); const session = require('koa-generic-session'); const bodyParser = require('koa-bodyparser'); const json = require('koa-json'); import Redis from 'koa-redis' const passport = require('./utils/passport') const dbconfig = require('./dbs/modules/db.config') const user = require('./router/user') const app = new Koa() const config = require('../nuxt.config.js') config.dev = app.env !== 'production' //设置session秘钥 app.keys = ['blog', 'keyskeys'] app.proxy = true app.use(session({ key: 'blog', prefix: 'blog:uid' })) mongoose.connect(dbconfig.dbs, { useNewUrlParser: true }) var db = mongoose.connection;//获取connection实例 //使用Connetion监听连接状态 db.on('connected', function (err) { if (err) { console.log('连接数据库失败:' + err); } else { console.log('连接数据库成功!'); } }); db.on("error", function (error) { console.log("数据库连接失败:" + error); }); db.on("open", function () { console.log("数据库连成功"); }); app.use(bodyParser()); app.use(json()); app.use(passport.initialize()) app.use(passport.session()) async function start() { // Instantiate nuxt.js const nuxt = new Nuxt(config) const { host = process.env.HOST || '127.0.0.1', port = process.env.PORT || 3000 } = nuxt.options.server // Build in development if (config.dev) { const builder = new Builder(nuxt) await builder.build() } else { await nuxt.ready() } app.use(user.routes()).use(user.allowedMethods()) app.use((ctx) => { ctx.status = 200 ctx.respond = false // Bypass Koa's built-in response handling ctx.req.ctx = ctx // This might be useful later on, e.g. in nuxtServerInit or with nuxt-stash nuxt.render(ctx.req, ctx.res) }) app.listen(port, host) consola.ready({ message: `Server listening on http://${host}:${port}`, badge: true }) } start()
编写路由
编写路由及守护中间件。
登录
POST /login
router.post('/login', async (ctx, next) => { return passport.authenticate('local', function (err, user, info, status) { console.log(err, user, info, status) if (err) { ctx.body = { code: -1, msg: err } } else if (user) { ctx.body = { code: 0, msg: '登录成功', user } console.log(ctx.body) return ctx.login(user) } else { ctx.body = { code: 1, msg: info } } })(ctx, next) })
登出
GET /logout
router.get('/logout', ctx => { ctx.logout() ctx.body = {auth: ctx.isAuthenticated(), user: ctx.state.user} })
路由守护中间件
比如你/api/*的路由需要用户认证才能访问
router.use('/api/*', (ctx, next) => { if(ctx.isAuthenticated()) { next() } else { ctx.status = 401 ctx.body = { msg: 'auth fail' } } })
到这里,本地权限认证基本完成了,post请求 /login 并且提交表单username,和 password即可登录一个用户。
/logout 退出当前登录。
解释
使用 passport 这个中间件,必须了解其运行步骤和知识点。
passport 以策略来扩展验证,什么是策略呢?
比如:本地策略,github登录策略,微信登录策略
passport 中间件使用前,需要注册策略,及实习序列化与反序列化操作。
序列化
通过 passport.serializeUser 函数定义序列化操作。
// 序列化passport.serializeUser(function(user, done) { done(null, user.id) })
在调用 ctx.login() 时会触发序列化操作。
反序列化
通过 passport.deserializeUser 函数定义反序列化操作。
// 反序列化 passport.deserializeUser(async function(id, done) { console.log('deserializeUser: ', id) var user = {id: 1, username: 'admin', password: '123456'} done(null, user) })
在请求时,session中如果存在 "passport":{"user":"xxx"}时会触发定义的反序列化操作
注册策略
// 策略 passport.use(new LocalStrategy({ // usernameField: 'email', // passwordField: 'passwd'}, function(username, password, done) { var user = {id: 1, username: username, password: password} done(null, user) }))
在使用 passport.authenticate('策略', ...) 的时候,会执行策略
其他
app.use(passport.initialize()) 会在请求周期ctx对象挂载以下方法与属性
ctx.state.user 认证用户
ctx.login(user) 登录用户(序列化用户)
ctx.isAuthenticated() 判断是否认证
发表评论
侧栏公告
寄语
譬如朝露博客是一个分享前端知识的网站,联系方式11523518。
热评文章
标签列表
热门文章
友情链接