簡介
Passport是一個Node.js中間件,它提供了易于實現(xiàn)的各種不同的請求身份驗證策略。默認(rèn)情況下,它將用戶對象存儲在會話中。 ? ?(推薦學(xué)習(xí):laravel開發(fā))
JSON Web令牌是一種身份驗證標(biāo)準(zhǔn),通過在有助于識別登錄用戶的請求中分配和傳遞加密令牌,而不是將用戶存儲在服務(wù)器上的會話中并創(chuàng)建cookie來工作。它有不同的集成,包括Node.js模塊。
安裝依賴項。
npm?install?--save?koa-passport??passport-jwt?jsonwebtoken
流程
當(dāng)用戶登錄時,后端會創(chuàng)建簽名令牌并將其作為響應(yīng)返回
客戶端在本地保存令牌(通常在localStorage中),并在每個需要身份驗證的后續(xù)請求中將其發(fā)回
所有需要身份驗證的請求都會通過中間件檢查提供的令牌,并且只有在驗證令牌時才允許請求
登錄時token
/** ?*?@route?POST?api/users/login ?*?@desc?用戶登錄接口 ?*?@access?都可訪問 ?*/ router.post('/login',?async?ctx?=>?{ ???? //...獲取數(shù)據(jù)?驗證數(shù)據(jù)省略 ????????const?payload?=?{ ????????????name:?user.name, ????????????email, ????????????avatar:?user.avatar ????????}; ????????//生成token ????????const?token?=?jwt.sign(payload,?config.secretKey,?{ ????????????expiresIn:?3600?//存活時間 ????????}); ????????ctx.status?=?200; ????????ctx.body?=?{ ????????????message:?'驗證成功', ????????????token:?'Bearer?'?+?token ????????} })
注: ‘Bearer ‘中間必須有個空格,大小寫也區(qū)分…
登錄解析Token
/** ?*?@route?GET?api/users/current ?*?@desc?獲取用戶信息 ?*?@access?私密接口 ?*/ ?//poassport.authenticate?則加入了認(rèn)證權(quán)限,會調(diào)用?passport.js中 router.get('/current',passport.authenticate('jwt',?{?session:?false?}),async?ctx=>{ //獲取?passport.js?中的返回值,去除密碼并將結(jié)果返回到客戶端 ????const?{password,...userInfo}=ctx.state.user._doc; ????ctx.body=userInfo; }) //app.js const?passport?=?require('koa-passport'); app.use(passport.initialize()) app.use(passport.session()) //調(diào)用?passport.js?并將passport傳入 require('./config/passport')(passport);
config/passport.js
const?config=require('./default'); const?JwtStrategy?=?require('passport-jwt').Strategy, ????ExtractJwt?=?require('passport-jwt').ExtractJwt; const?opts?=?{} opts.jwtFromRequest?=?ExtractJwt.fromAuthHeaderAsBearerToken(); opts.secretOrKey?=?config.secretKey; //?const?User=require('../models/User'); const?mongoose=require('mongoose'); const?User=mongoose.model('users'); module.exports=passport=>{ ????passport.use(new?JwtStrategy(opts,async?(jwt_payload,done)=>{ ???? //jwt_payload?返回的是登錄時返回的數(shù)據(jù)?即payload ????????const?user=await?User.findOne(jwt_payload.id); ????????if(user){ ????????????done(null,user); ????????}else{ ????????????done(null,false); ????????} ????})) }
ps. 這是用戶登錄模板完整代碼
app.js
const?Koa=require('koa'); const?KoaRouter=require('koa-router'); const?bodyParser=require('koa-bodyparser'); const?mongoose=require('mongoose'); //const?config=require('./config/default') const?passport?=?require('koa-passport'); //配置文件?這里就不單獨抽離 const?config={ mogoUrl:'mongodb://localhost/koaTest', ????secretKey:'sercretKey', } const?router=new?KoaRouter(); const?app=new?Koa(); app.use(bodyParser()); //初始化?passport app.use(passport.initialize()) app.use(passport.session()) //連接數(shù)據(jù)庫 mongoose.connect(config.mogoUrl,{ ????useNewUrlParser:true }).then(res=>{ ????console.log('mongoose?connectd...'); }) .catch(error=>{ ????console.log(error) }) //引入?user.js const?user=require('./routes/api/user'); require('./config/passport')(passport); //配置路由地址 router.use('/api/users',user); //配置路由 app.use(router.routes()).use(router.allowedMethods()); const?port=process.env.PORT||5000; //監(jiān)聽端口 app.listen(port,()=>{ ????console.log(`listing?at?${port}`) })
routes/api/user.js
var?Router?=?require('koa-router'); var?router?=?new?Router(); const?User?=?require('../../models/User') const?bcrypt?=?require('bcryptjs'); const?tools?=?require('../../config/tools') const?jwt?=?require('jsonwebtoken');?//token?認(rèn)證 const?config?=?require('../../config/default'); const?passport=require('koa-passport'); /** ?*?@route?POST?api/users/login ?*?@desc?用戶登錄接口 ?*?@access?都可訪問 ?*/ router.post('/login',?async?ctx?=>?{ ????const?{ ????????email, ????????password ????}?=?ctx.request.body; ????const?findResult?=?await?User.find({ ????????email ????}); ????const?user?=?findResult[0]; ????if?(findResult.length?===?0)?{ ????????//表示不存在該用戶 ????????ctx.status?=?404; ????????ctx.body?=?{ ????????????message:?'該用戶不存在' ????????}; ????????return; ????} ????//驗證密碼是否正確 ????const?verify?=?bcrypt.compareSync(password,?user.password); ????if?(verify)?{ ????????//密碼正確 ????????const?payload?=?{ ????????????name:?user.name, ????????????email, ????????????avatar:?user.avatar ????????}; ????????//生成token ????????const?token?=?jwt.sign(payload,?config.secretKey,?{ ????????????expiresIn:?3600 ????????}); ????????ctx.status?=?200; ????????ctx.body?=?{ ????????????message:?'驗證成功', ????????????token:?'Bearer?'?+?token ????????} ????}?else?{ ????????ctx.status?=?500; ????????ctx.body?=?{ ????????????message:?'密碼錯誤' ????????}; ????} }) /** ?*?@route?GET?api/users/current ?*?@desc?獲取用戶信息 ?*?@access?私密接口 ?*/ router.get('/current',passport.authenticate('jwt',?{?session:?false?}),async?ctx=>{ ????const?{password,...userInfo}=ctx.state.user._doc; ????ctx.body=userInfo; }) module.exports?=?router.routes();
? 版權(quán)聲明
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載。
THE END