Heim >Web-Frontend >js-Tutorial >Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren

Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren

青灯夜游
青灯夜游nach vorne
2022-12-06 19:49:151938Durchsuche

Was ist Single Sign-On? Was ist das Prinzip? Wie erreicht man es? Der folgende Artikel führt Sie durch Single Sign-On und erläutert, wie Sie Node zur Implementierung von Single Sign-On SSO verwenden. Ich hoffe, er wird Ihnen hilfreich sein!

Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren

【Empfohlene verwandte Tutorials: nodejs-Video-Tutorial, Programmierlehre

Was ist Single Sign-On? Mit zunehmendem Geschäftsvolumen des Unternehmens werden zwangsläufig unterschiedliche Systeme erstellt sehr unpraktisch sein, wenn das System separate Anmeldungen erfordert.

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.

Prinzip des Single Sign-On

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: Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren

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, 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ückkommt, 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, springt zurück zur Anwendungs-B-Adresse und hängt an das Token-Token
  • 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 sie an Ressourcen und Benutzeranmeldestatus beibehalten
  • NodeJS-Demonstration
Drei verschiedene Dienste

Hier müssen wir drei Dienste starten, um Anwendung A, SSO-Authentifizierungsserver bzw. Anwendung B zu simulieren

Die 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 an

const 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 AnmeldeseiteLassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren

Authentifizierungsserver SSO

Die 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

Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementierenAuth/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`)
})

Gerade haben wir von Anwendung A aus begonnen und springen zu , um die Logik in der Anmeldung anzuzeigen Token erstellenAuth /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

trägt das Token vom Authentifizierungsserver und springt zurück zu Anwendung A

Token-Überprüfung gibt Ressourcen zurück

Anwendung A

<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=&#39;登录&#39;></div>
    </form>
</body>
</html>

verarbeitet die Überprüfung Token im entsprechenden SSO Die Logik der Karte

Auth/routes/check-token

router.post(&#39;/&#39;,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(&#39;token&#39;,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:&#39;用户名或密码错误&#39;
       }
   }
})
Lassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementierenAuth/service/index.js

app.use(views(path.join(__dirname,&#39;./views&#39;)),{
    extension:&#39;ejs&#39;
  })

//...

const system=process.env.SERVER_NAME
router.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 = 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(&#39;index.ejs&#39;,{
                        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}`)

})

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.

访问应用B

带cookie跳转至SSO认证服务器

应用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(&#39;/&#39;,async (ctx)=>{
  const cookies=ctx.cookies;
  const token=cookies.get(&#39;token&#39;);
  //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,&#39;./views&#39;)),{
    extension:&#39;ejs&#39;
  })

//...

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(&#39;index.ejs&#39;,{
                        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(&#39;index.ejs&#39;,{
              user,
              system
        })
    }
    //...
 })

原文地址:https://juejin.cn/post/7088343138905325582

作者:YoYo君

更多node相关知识,请访问:nodejs 教程

Das obige ist der detaillierte Inhalt vonLassen Sie uns darüber sprechen, wie Sie Single Sign-On (SSO) basierend auf Node implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen