什么是單點登錄?怎么使用Nodejs實現SSO( 二 )


Auth/index.js
const Koa=require('koa');const Router=require('koa-router')const views=require('koa-views')const path=require('path');const app=new Koa();const router=new Router();const login=require("./routes/login")const checkToken=require('./routes/check-token')const bodyparser=require('koa-bodyparser')app.use(views(path.join(__dirname,'./views')),{ extension:'ejs' })app.use(bodyparser())//處理登錄相關的邏輯router.use('/login',login.routes())//處理令牌驗證的邏輯router.use('/check_token',checkToken.routes())app.use(router.routes())app.listen(8383,()=>{ console.log(`app listen at 8383`)})剛才我們從應用A跳轉到 http://localhost:8383/login?redirectUrl=localhost:8686來看login中的邏輯
Auth/routes/login.js
const service = require("../service");const router=require("koa-router")()router.get('/',async (ctx)=>{ const cookies=ctx.cookies; const token=cookies.get('token'); //從cookie中判斷應用A的登錄態 if(token && service.isTokenVailid(token)){ // 。 。 。 如果有登錄過 }else{ //2、SSO認證中心發現用戶沒有登錄過, 于是渲染登錄頁面登錄頁面; await ctx.render('login.ejs',{ extension:'ejs' }) }})// 。 。 。 module.exports=router登錄頁面
Auth/views/login.ejs
<html><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>統一登錄</title></head><body> <h1>統一登錄</h1> <form method="post"> <div>用戶名: <input type="text" name="name"/></div> <div>密碼 <input type="text" name="password" /></div> <div><input type="submit" value=https://www.52zixue.com/zhanzhang/webqd/js/04/23/70557/'登錄'>

校驗用戶信息, 創建令牌
Auth/routes/login.js
router.post('/',async (ctx)=>{//2、用戶填寫用戶名密碼提交登錄申請; const body=ctx.request.body; const {name,password}=body; //2、SSO認證中心校驗用戶信息, if(name==="admin" && password==="123456"){ //2、創建用戶雨SSO認證中心的會話(這時會把信息保存到cookie中), 同時創建授權令牌token const token="passport"; await ctx.cookies.set('token',token,{ maxAge:1000*60*60*24*30, httpOnly:true }) if(ctx.query.redirectUrl){ //3、sso認證中心帶著令牌跳轉到最初的請求地址(應用A) ctx.redirect(`${ctx.protocol}://${ctx.query.redirectUrl}?token=${token}`) //回跳地址是 http://localhost:8686/?token=passport }else{ ctx.body="<h1>登錄成功!</h1>" } }else{ ctx.response.body={ error:1, msg:'用戶名或密碼錯誤' } }})從認證服務器攜帶令牌跳轉回應用A
令牌校驗 返回資源
應用A
app.use(views(path.join(__dirname,'./views')),{ extension:'ejs' })//...const system=process.env.SERVER_NAMErouter.get("/",async (ctx)=>{ let user=ctx.session.user if(user){ //... } else //這時應用A依舊沒有登錄態 但url上有了令牌 http://localhost:8686/?token=passport { let token=ctx.query.token if(!token) { //...跳轉去SSO登錄頁面 } else //跳回應用A時走這里的邏輯 { //ajax請求 4. 應用A拿到令牌去SSO認證中心認證是否有效, 如果返回有效注冊應用A const url=`://localhost:8383/check_token?token=${token}&t=${new Date().getTime()}` let data = https://www.52zixue.com/zhanzhang/webqd/js/04/23/70557/await koa2Req(ctx.protocol + url); if(data && data.body){ try { const body=JSON.parse(data.body) const {error,userId}=body; // console.log(error,userId) 0,admin if(error==0){ if(!userId){ ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`) return } //驗證通過后注冊session, 渲染頁面 //5. 應用A創建與用戶之間的會話, 展示資源并維持用戶登錄態 ctx.session.user=userId; await ctx.render('index.ejs',{ user:userId, system }) }else{ ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`) } } catch (error) {console.log(error)} } } }})app.use(router.routes())const port=process.env.PORT||8888app.listen(port,()=>{ console.log(`app ${system} running at ${port}`)})與之對應的 SSO中處理驗證令牌的邏輯
Auth/routes/check-token
const router=require("koa-router")()const service=require("../service")router.get('/',async (ctx)=>{ const token=ctx.query.token; const result={ error:1 } //當token 是 password時 if(service.isTokenVailid(token)){ result.error=0; result.userId='admin' } ctx.body=result })module.exports=router

推薦閱讀