Heim > Artikel > Web-Frontend > Was ist Single Sign-On? So implementieren Sie SSO mit Nodejs
Was ist Single Sign-On? Der folgende Artikel führt Sie in das Prinzip des Single Sign-On ein und erläutert die Methode zur Verwendung von Node zur Implementierung von Single Sign-On SSO. Ich hoffe, er wird Ihnen hilfreich sein!
Mit zunehmendem Geschäftsvolumen des Unternehmens werden zwangsläufig unterschiedliche Systeme generiert. Es ist sehr unpraktisch, wenn für jedes System eine separate Anmeldung erforderlich ist.
So entstand eine Lösung wie Single Sign-On. Der vollständige Name von Single Sign-On lautet Single Sign On, kurz SSO. Dies bedeutet, dass Sie sich bei einem System in mehreren Systemanwendungsgruppen anmelden können in allen anderen Systemen ohne erneute Anmeldung autorisiert werden.
Zum Beispiel hat sich Xiao Ming heute bei Taobao angemeldet, er wird aufgefordert, Authentifizierungsinformationen (Benutzername, Passwort usw.) einzugeben, wenn er die Seite von Tmall besucht direkt ohne Anmeldung.
SSO erfordert eine unabhängige Zertifizierungsstelle, die den Benutzernamen, das Passwort und andere Sicherheitsinformationen des Benutzers akzeptieren kann die der Zertifizierungsstelle. Der gesamte Vorgang kann einfach mit dem Bild oben beschrieben werden:
Wenn sich der Benutzer anmeldet, um auf Anwendung A zuzugreifen, stellt Anwendung A fest, dass der Benutzer nicht angemeldet ist, springt zum SSO-Authentifizierungscenter und verwendet seine eigene Adresse als ein Parameter zur Erleichterung von Rückrufen
SSO Das Authentifizierungscenter stellt fest, dass sich der Benutzer noch nicht angemeldet hat, und leitet den Benutzer zur Anmeldeseite weiter. Der Benutzer gibt den Benutzernamen und das Kennwort ein, um einen Anmeldeantrag einzureichen Erstellen Sie die Benutzerinformationen und erstellen Sie eine Sitzung zwischen dem Benutzer und dem SSO-Authentifizierungszentrum (die Informationen werden zu diesem Zeitpunkt in einem Cookie gespeichert) und erstellen Sie gleichzeitig ein Autorisierungstoken. Das SSO-Zertifizierungszentrum springt zur ursprünglichen Anfrage Adresse (Anwendung A) mit dem Token
Anwendung A erhält das Token und geht zum SSO-Zertifizierungszentrum, um zu überprüfen, ob es gültig ist. Wenn es zurückgegeben wird, registrieren Sie Anwendung A effektiv.
Anwendung A erstellt eine Sitzung mit dem Benutzer, zeigt Ressourcen an und behält den Anmeldestatus des Benutzers bei
Wenn der Benutzer auf Anwendung B zugreift, wird festgestellt, dass der Benutzer nicht angemeldet ist (der SSO-Authentifizierungsserver und Anwendung A und Anwendung B sind nicht dieselbe Domäne und können den Anmeldestatus nicht bereitstellen ), springen Sie zum SSO-Zertifizierungszentrum und bringen Sie Ihre Adress- und Cookie-Informationen aus der vorherigen Sitzung mit dem SSO-Zertifizierungszentrum mit
Das SSO-Zertifizierungszentrum stellt fest, dass der Benutzer angemeldet ist und springt zurück zur Anwendungs-B-Adresse und Hängen Sie das Token-Token an
Die gleiche Anwendung B erhält das Token und geht zum SSO-Zertifizierungszentrum, um zu überprüfen, ob es gültig ist. Wenn es eine gültige registrierte Anwendung B zurückgibt, erstellt Anwendung B eine Sitzung mit dem Benutzer und zeigt Ressourcen an und behält den Benutzeranmeldestatus bei
Der Dienst mit der Portnummer 8383 ist hier der SSO-Authentifizierungsserver, und der Rest: 8686 und :8787 repräsentieren Anwendung A bzw. Anwendung B.
Tatsächlich sind die Codes von Anwendung A und Anwendung B fast gleich. Wie in der Abbildung oben gezeigt, können wir durch Übergabe von Parametern unterschiedliche Ports und Anwendungsnamen festlegen. Schauen wir uns zunächst den Effekt anconst Koa=require('koa'); const Router=require('koa-router') const views=require('koa-views') const static=require('koa-static') const path=require('path'); const app=new Koa(); const router=new Router(); const session=require('koa-session') const koa2Req=require('koa2-request'); //模版引擎相关配置 app.use(views(path.join(__dirname,'./views')),{ extension:'ejs' }) app.keys=['key'] const keyMap={ '8686':'koa:sess8686', '8787':'koa:sess8787' } const CONFIG={ key:keyMap[process.env.PORT] || 'koa:sess', maxAge:1000*60*60*24, httpOnly:true } app.use(session(CONFIG,app)) const system=process.env.SERVER_NAME router.get("/",async (ctx)=>{ //通过 session来判断 应用A的登录状态 let user=ctx.session.user if(user){ //... } else //1、当用户登录访问应用A时,应用A发现用户未登录(应为服务器没有保存对应的session) { let token=ctx.query.token //第一次登录url上也不会有令牌 if(!token) { //1、跳转到SSO认证服务器 ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`) } else { //... } } }) app.use(router.routes()) const port=process.env.PORT||8888 app.listen(port,()=>{ console.log(`app ${system} running at ${port}`) })Authentifizierungsserver zur Bestimmung des Anmeldestatus, Rendern der AnmeldeseiteAuthentifizierungsserver SSODie Verzeichnisstruktur des Authentifizierungsservers ist wie folgt Es übernimmt hauptsächlich zwei Funktionen, eine ist die Anmeldelogik und die andere ist die anschließende Überprüfung der Gültigkeit des Tokens, die durch Weiterleiten von login.js bzw. check-token.js erledigt werden
Auth/Index. js Token erstellen
Auth /routes/login.jsconst 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`)
})
trägt das Token vom Authentifizierungsserver und springt zurück zu Anwendung A
Token-Überprüfung gibt Ressourcen zurück
Anwendung Aconst 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
verarbeitet die Überprüfung Token im entsprechenden SSO Die Logik der Karte
<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='登录'></div> </form> </body> </html>Auth/service/index.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:'用户名或密码错误' } } })An diesem Punkt kann der Benutzer normal auf Anwendung A und die Anmeldeinformationen des Benutzers zugreifen ist auf dem SSO-Server und dem Anwendungs-A-Server verfügbar.
Besuchen Sie Anwendung B
http://localhost:8383/login?redirectUrl=localhost:8686
Anwendung B
//... router.get("/",async (ctx)=>{ let user=ctx.session.user if(user){ //... }else{ let token=ctx.query.token //... if(!token) { //同样既没有session也没有令牌,跳转到SSO认证服务器 //6、当用户访问应用B时,发现用户未登录(SSO认证服务器与应用A应用B不是同一个域,不能提供登录态),跳转到SSO认证中心,并将自己的地址和之前和SSO认证中心会话的cookie信息带入 ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`) } else { //。。。验证令牌的部分 } } }) app.use(router.routes()) const port=process.env.PORT||8888 app.listen(port,()=>{ console.log(`app ${system} running at ${port}`) })
从认证服务器携带令牌跳转回应用B
SSO认证服务器 ,再次登录时携带了cookie,因此不会再请求登录页面 Auth/routes/login
//... router.get('/',async (ctx)=>{ const cookies=ctx.cookies; const token=cookies.get('token'); //7. SSO认证中心发现用户已登录,跳转回应用B地址,并附上令牌token if(token && service.isTokenVailid(token)){ const redirectUrl=ctx.query.redirectUrl; if(redirectUrl){ //带着令牌跳转回应用B ctx.redirect(`${ctx.protocol}://${redirectUrl}?token=${token}`) }else{ ctx.body="<h1>登录成功!</h1>" } }else{ //...渲染登录页面 } }) //..
令牌校验 返回资源
这里的逻辑和5,6两步一样,因为token容易伪造,所以要检验真伪。 应用B
app.use(views(path.join(__dirname,'./views')),{ extension:'ejs' }) //... const system=process.env.SERVER_NAME router.get("/",async (ctx)=>{ let user=ctx.session.user if(user){ //... } else //这时应用B依旧没有登录态 但url上有了令牌 http://localhost:8787/?token=passport { let token=ctx.query.token if(!token) { //...跳转去SSO登录页面 } else //跳回应用B时走这里的逻辑 { //ajax请求 8. 同样的应用B拿到令牌去SSO认证中心认证是否有效,如果返回有效注册应用B const url=`://localhost:8383/check_token?token=${token}&t=${new Date().getTime()}` let data = 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,渲染页面 //9. 应用B创建与用户之间的会话,展示资源并维持用户登录态 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||8888 app.listen(port,()=>{ console.log(`app ${system} running at ${port}`) })
至此单点登录的大部分逻辑都已经完成,之后再session有效期内再访问页面,就不需要再登录,直接返回资源
router.get("/",async (ctx)=>{ //如果session中有用户信息,说明已经登录过,直接返回请求资源 let user=ctx.session.user if(user){ await ctx.render('index.ejs',{ user, system }) } //... })
原文地址:https://juejin.cn/post/7088343138905325582
作者:YoYo君
更多node相关知识,请访问:nodejs 教程!
Das obige ist der detaillierte Inhalt vonWas ist Single Sign-On? So implementieren Sie SSO mit Nodejs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!