Express 在同一浏览器上同时访问两个应用程序模块且用户尚未登录时,授予提供程序OAuth状态不匹配

Express 在同一浏览器上同时访问两个应用程序模块且用户尚未登录时,授予提供程序OAuth状态不匹配,express,oauth-2.0,single-sign-on,express-session,grant-oauth,Express,Oauth 2.0,Single Sign On,Express Session,Grant Oauth,我一直在尝试实现单点登录(SSO)。我有不同的前端应用程序模块,它们运行在不同的域上,它们都使用单个API服务器 单点登录服务器 API服务器 前端模块1 前端模块2 认证流 身份验证的流程是前端模块检查本地存储中的令牌。如果找不到令牌,它会将用户重定向到API服务器端点,比如说。 API服务器具有SSO服务器的客户端ID和机密。API服务器在cookie中设置前端模块的url(以便我可以将用户重定向回启动器前端模块),然后将请求重定向到SSO服务器,在该服务器上,用户将显示登录屏幕。用户在那里

我一直在尝试实现单点登录(SSO)。我有不同的前端应用程序模块,它们运行在不同的域上,它们都使用单个API服务器

  • 单点登录服务器
  • API服务器
  • 前端模块1
  • 前端模块2
  • 认证流 身份验证的流程是前端模块检查本地存储中的令牌。如果找不到令牌,它会将用户重定向到API服务器端点,比如说。 API服务器具有SSO服务器的客户端ID和机密。API服务器在cookie中设置前端模块的url(以便我可以将用户重定向回启动器前端模块),然后将请求重定向到SSO服务器,在该服务器上,用户将显示登录屏幕。用户在那里输入凭据,SSO服务器验证凭据,创建会话。 验证凭证后,SSO服务器使用用户配置文件和访问令牌调用API服务器端点。API服务器在会话和查询中获取配置文件,并对自己的令牌进行签名,然后通过查询参数将其发送到前端模块。在前端(React应用程序)上有一条专门用于此目的的路线。在该前端路由中,我从queryParams中提取令牌并在localstorage中设置。用户在应用程序中。 同样,当用户加载FrontendModule-2时,也会发生相同的流,但这一次是因为在FrontendModule-1流运行时,SSO服务器正在创建会话。它从不要求用户提供登录凭据并登录系统

    失败情景: 该场景是,假设有一个用户JHON尚未登录并且没有会话。Jhon在浏览器中点击“前端模块1”URL。前端模块检查本地存储中的令牌,但在那里找不到,然后前端模块将用户重定向到API服务器路由。 API服务器具有将请求重定向到SSO服务器的clientSecret和clientId。将向用户显示登录屏幕

    Jhon看到登录屏幕并保持原样。现在,Jhon在同一浏览器中打开另一个选项卡,并输入“前端模块2”的URL。同样的流程如上所述,Jhon登陆登录屏幕。Jhon离开了原来的屏幕,移回第一个选项卡,在那里加载了前端模块1会话屏幕。他输入creds并点击登录按钮。会话状态已更改,这给了我一个错误。 这个错误实际上是有道理的,因为会话是共享的

    期望值 如何在没有错误的情况下实现这一点。我想将用户重定向到发起请求的同一前端模块

    我正在使用的工具

    示例实现(API服务器)
    require('dotenv').config();
    var express=require('express')
    ,session=require('express-session')
    ,morgan=require('morgan')
    var Grant=require('Grant-express')
    ,port=process.env.port | | 3001
    ,oauthConsumer=process.env.OAUTH|u CONSUMER |`http://localhost`
    ,oauthProvider=process.env.OAUTH_PROVIDER|URL|http://localhost'
    ,grant=new grant({
    默认值:{
    协议:“https”,
    主持人:oauthConsumer,
    运输:"会议",,
    国家:对
    },
    MyAuth:{
    关键字:process.env.CLIENT|u ID | |“test”,
    秘密:process.env.CLIENT|u secret | |“secret”,
    重定向\u uri:`${oauthConsumer}/connect/myOAuth/callback`,
    authorize\u url:`${oauthProvider}/oauth/authorize`,
    访问url:“${oauthProvider}/oauth/token`,
    非统组织:2,
    作用域:['openid','profile'],
    回调:'/done',
    作用域分隔符:“”,
    动态:['uiState'],
    自定义参数:{deviceId:'abcd',appId:'com.pud'}
    }
    })
    var app=express()
    应用程序使用(摩根(‘开发’))
    //必需:(任何会话存储-请参阅./examples/express session)
    使用(会话({secret:'grant'}))
    //在Grant的动态键中设置FrontEndModule URL。
    应用程序使用((请求、恢复、下一步)=>{
    req.locals.grant={
    动态:{
    uiState:req.query.uiState
    }
    }
    next();
    })
    //格兰特山
    应用程序使用(授权)
    app.get('/done',(req,res)=>{
    if(请求会话授予响应错误){
    res.status(500.json)(req.session.grant.response.error);
    }否则{
    res.json(req.session.grant);
    }
    })
    应用程序侦听(端口,()=>{
    log(`READY port${port}`)
    })
    在点击SSO服务器时,您有中继状态选项,该选项在发送到SSO服务器时返回,只是为了在请求SSO之前跟踪应用程序状态

    要了解有关中继状态的更多信息,请执行以下操作:


    您使用的是哪种SSO服务???

    您必须将用户重定向回原始应用程序URL,而不是API服务器URL:

    。使用('/connect/:provider',(req,res,next)=>{
    res.locals.grant={dynamic:{redirect\u uri:
    `http://${req.headers.host}/connect/${req.params.provider}/callback`
    }}
    下一个()
    })
    .use(grant(require('./config.json')))
    
    然后,您需要同时指定以下两项:

    https://foo1.bar.com/connect/google/callback
    https://foo2.bar.com/connect/google/callback
    
    允许重定向OAuth应用程序的URI

    最后,您必须将一些应用程序域路由路由路由到Grant正在处理重定向URI的API服务器

    例子
  • 使用以下重定向URI
    https://foo1.bar.com/connect/google/callback
  • 导航到
    https://foo1.bar.com/login
    在您的浏览器应用程序中
  • 浏览器应用程序重定向到您的API
    https://api.bar.com/connect/google
  • 在将用户重定向到Google之前,上面的代码根据请求到
    的传入
    Host
    头配置
    重定向uri
    https://foo1.bar.com/connect/google/callback
  • 用户登录到谷歌,并被重定向回
    https://foo1.bar.com/connect/google/callback
  • 必须将该特定路径重定向回API
    https://api.bar.com/connect/g