想用passport模块肯定先要引passport的包,但是除了passport的包,每加一种验证策略就需要再加一个包,正常来说都是需要本地验证策略的,所以就要加passport-local模块,如果想要qq登录,就需要加passport-qq模块,想要其他的就再加其他模块。
下面先介绍本地验证:
本地验证
const passport = require('koa-passport');
const LocalStrategy = require('passport-local').Strategy;
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy({
usernameField:'username',
//说明用户名就是ctx.request.body.username,指明了下面函数中的username参数是谁,password同理
passwordField:'password',
passReqToCallback:true,
},
async function (ctx,username,password,done){
let captcha = ctx.body.captcha;
let captchaDate = ctx.session.captchaDate;
let realCaptcha = ctx.session.captcha;
let user = await User.findOne({username})
return done(null,false/*user*/,'未知用户');
/*done的第一个参数为错误信息,没有就返回null,第二个参数为用户信息(验证失败则为false),第三个为错误信息*/
}
))
序列化和反序列化的对象是session,是将信息存入session,和将信息从session中取出来。(要存入的变量可以是一个String或者Number或Object)
- 序列化函数:serializeUser,在ctx.login(id)函数调用时触发,其中的参数会传给serializeUser函数作为其第一个参数,
- 反序列化函数:deserializeUser,会自动解析用户请求中session的信息,并作为回调函数的第一个参数,如果在serializeUser函数中将ID信息存入session,则在这一步回调函数的第一个参数就是ID,在此时可以根据ID查询数据库从而获取用户的更多信息。
/*序列化在ctx.login()函数调用时触发,会自动在ctx.state.user中添加done中的第二个参数,并在session中添加用户登*/录状态
passport.serializeUser((user,done)=>{
return done(null,{_id:user._id,username:user.username,avatar:user.avatar});
})
/*反序列化,会在用户请求到来的时候从session中解析用户信息,如果在登录状态,则在ctx.state.user中添加ctx.login()函数执行时添加进去的参数*/
passport.deserializeUser(function (user, done) {
return done(null, {_id:user._id,username:user.username,avatar:user.avatar})
})
POST—>/login时:
router.post('/',async ctx=>{
return passport.authenticate('local',
async function(err, user, info){
/*这是回调函数,这里的四个参数就是策略中的done返回的三个参数,当然这都是由自己决定的,可以选择返回更多或更少的参数*/
if(info == '判断条件'){
ctx.status = 301;
ctx.redirect(`/v1/register/${user.username}`);
}
if(user){
ctx.body = {
code:1,
message:'登陆成功',
data:{
//返回给客户端的数据
}
}
return ctx.login({_id:user._id,username:user.username,avatar:user.avatar});
//这里调用ctx.login()函数传入的参数要和上文中的序列化函数passport.serializeUser对应
}else{
ctx.body = {
code:-1,
message:info,
data:{}
}
return ;
}
})(ctx);//此处将ctx传入本地验证策略函数
});
当你在其他路由中需要验证用户是否登录的时候就可以通过ctx.isAuthenticated()函数,这样:
router.use("/user",async (ctx, next) => {
if(ctx.isAuthenticated()) {
await next();
}else{
ctx.status = 401;
ctx.body = {
code:-3,
msg: '请先登录',
}
}
})
- 以上有三个方法login,logout,isAuthenticated,是passport模块加进来的方法,出了这三个还有一个isUnauthenticated,其作用和isAuthenticated相反,除了login方法外,其他三个都不带参数