Forge 3-Legged Oauth - 以另一个用户身份登录/强制注销

Forge 3-Legged Oauth - Sign in as another User / Force logout

我有 3 条腿去上班,我有自己的 session login/logout 管理。

注销后,如果用户想再次登录,我将他发送到 https://developer.api.autodesk.com/authentication/v1/authorize,它直接进入我的回调,之前的用户已经通过身份验证,而不是提示新登录。

Autodesk 似乎将 session 存储为 cookie,因此授权后切换用户的唯一方法是清除浏览器 cache/data

有没有办法强制注销,或者类似于"Sign in as another user"的方法?

这是我第一次做 oauth,所以我不确定我是否遗漏了什么,但似乎应该有办法强制清除 session 并强制重新登录。


编辑

让我进一步阐明我要实现的目标:

这是我的资料。 1. 我将用户定向到身份验证页面,并将其定向到: https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id=obQDn8P0GanGFQha4ngKKVWcxwyvFAGE&redirect_uri=http%3A%2F%2F{{mycallback}}%2Fcallback%3Ffoo%3Dbar&scope=data:read

  1. 用户使用他的 Autodesk 凭据登录

  2. 授权流程将用户重定向到`mycallback.com/callback/?code={{code}}

  3. 我的后端从 url 请求中获取 code 参数,并向 https://developer.api.autodesk.com/authentication/v1/gettoken

    [ 发出 POST 请求=74=]
  4. 请求 returns,除其他外,access_token

  5. 我将 access_token 存储到用户的 session,并使用它向 API 发出下一个请求。

至此,一切如我所愿。现在我想注销用户,并可能以其他用户身份登录。

  1. 我服务器上的一个 /logout 端点清除了用户 session,删除了存储的 access_token。

  2. 一旦后端意识到没有活动 session/access_token,它会将用户重定向到身份验证流程(上面的步骤 #1)。

  3. 此时,我本以为会看到另一个Autodesk登录页面,但Autodesk的服务器却在没有新登录的情况下自动授权,并重定向用户回调,用户再次登录。

所以换句话说我的问题,如何改变上面 #9 的行为,以便用户必须 re-enter 他的凭据?

我 运行 在开发过程中经常遇到这种情况,我用我的个人帐户登录,然后注销,我想用我的工作帐户登录。 目前,我能做到这一点的唯一方法是清除浏览器的缓存。 这让我认为 Autodesk 将 session 存储在浏览器中,这就是为什么在没有获得新凭据的情况下它是 re-authenticating 的原因。

同样的行为发生在你的dm.autodesk.io 第一次登录后,如果我再次尝试授权,则不会提示我第二次登录,而是在我登录的第一个用户中自动 re-logins。

如果我理解正确发生了什么,似乎 API 应该有一个 end-point ,当我用户注销时我们可以调用它来强制 re-authentication.

有道理吗?

谢谢!

我不确定你所说的 "I send him to https://developer.api.autodesk.com/authentication/v1/authorize" 是什么意思,但这必须发生在你的服务器上。

https://dm.autodesk.io 检查我的示例:允许弹出窗口并单击导航栏中的 "User Data"。登录后,用户会话将安全地存储在服务器上。如果您重新加载页面,它将自动让您登录。如果您再次单击导航栏按钮,它将清除服务器上的会话,如果您重新加载,您将不会登录。我想这就是您正在寻找的行为。

此项目的代码位于 there. The 3-legged logic is handled from there,如下所示 (node.js):

import ServiceManager from '../services/SvcManager'
import { serverConfig as config } from 'c0nfig'
import { OAuth2 } from 'oauth'
import express from 'express'

module.exports = function() {

  var router = express.Router()

  ///////////////////////////////////////////////////////////////////////////
  // 2-legged client token: exposes a 'data:read' only token to client App
  //
  ///////////////////////////////////////////////////////////////////////////
  router.get('/token/2legged', async(req, res) => {

    try {

      var forgeSvc = ServiceManager.getService('ForgeSvc')

      var token = await forgeSvc.request2LeggedToken('data:read')

      res.json(token)

    } catch (error) {

      res.status(error.statusCode || 404)
      res.json(error)
    }
  })

  /////////////////////////////////////////////////////////////////////////////
  // Initialize OAuth library
  //
  /////////////////////////////////////////////////////////////////////////////

  var oauth2 = new OAuth2(
    config.forge.oauth.clientId,
    config.forge.oauth.clientSecret,
    config.forge.oauth.baseUri,
    config.forge.oauth.authorizationUri,
    config.forge.oauth.accessTokenUri,
    null)

  /////////////////////////////////////////////////////////////////////////////
  // login endpoint
  //
  /////////////////////////////////////////////////////////////////////////////
  router.post('/login', function (req, res) {

    var authURL = oauth2.getAuthorizeUrl({
      redirect_uri: config.forge.oauth.redirectUri,
      scope: config.forge.oauth.scope.join(' ')
    })

    res.json(authURL + '&response_type=code')
  })

  /////////////////////////////////////////////////////////////////////////////
  // logout endpoint
  //
  /////////////////////////////////////////////////////////////////////////////
  router.post('/logout', (req, res) => {

    var forgeSvc = ServiceManager.getService(
      'ForgeSvc')

    forgeSvc.delete3LeggedToken(req.session)

    res.json('success')
  })

  /////////////////////////////////////////////////////////////////////////////
  // Reply looks as follow:
  //
  //  access_token: "fk7dd21P4FAhJWl6MptumGkXIuei",
  //  refresh_token: "TSJpg3xSXxUEAtevo3lIPEmjQUxXbcqNT9AZHRKYM3",
  //  results: {
  //    token_type: "Bearer",
  //    expires_in: 86399,
  //    access_token: "fk7dd21P4FAhJWl6MptumGkXIuei"
  //  }
  //
  /////////////////////////////////////////////////////////////////////////////
  router.get('/callback/oauth', (req, res) => {

    var socketSvc = ServiceManager.getService(
      'SocketSvc')

    // filter out errors (access_denied, ...)
    if (req.query && req.query.error) {

      if (req.session.socketId) {

        socketSvc.broadcast(
          'callback', req.query.error,
          req.session.socketId)
      }

      res.json(req.query.error)
      return
    }

    if(!req.query || !req.query.code) {

      res.status(401)
      res.json('invalid request')
      return
    }

    oauth2.getOAuthAccessToken(
      req.query.code, {
        grant_type: 'authorization_code',
        redirect_uri: config.forge.oauth.redirectUri
      },
      function (err, access_token, refresh_token, results) {

        try {

          var forgeSvc = ServiceManager.getService(
            'ForgeSvc')

          var token = {
            scope: config.forge.oauth.scope,
            expires_in: results.expires_in,
            refresh_token: refresh_token,
            access_token: access_token
          }

          forgeSvc.set3LeggedTokenMaster(
            req.session, token)

          if(req.session.socketId) {

            socketSvc.broadcast(
              'callback',
              'success',
              req.session.socketId)
          }

          res.end('success')

        } catch (ex) {

          res.status(500)
          res.end(ex)
        }
      }
    )
  })

  /////////////////////////////////////////////////////////////////////////////
  // logout route
  //
  /////////////////////////////////////////////////////////////////////////////
  router.post('/logout', (req, res) => {

    var forgeSvc = ServiceManager.getService(
      'ForgeSvc')

    forgeSvc.logout(req.session)

    res.json('success')
  })

  ///////////////////////////////////////////////////////////////////////////
  // 3-legged client token: exposes a 'data:read' only token to client App
  //
  ///////////////////////////////////////////////////////////////////////////
  router.get('/token/3legged', async (req, res) => {

    var forgeSvc = ServiceManager.getService(
      'ForgeSvc')

    try {

      var token = await forgeSvc.get3LeggedTokenClient(
        req.session)

      res.json({
        expires_in: forgeSvc.getExpiry(token),
        access_token: token.access_token,
        scope: token.scope
      })

    } catch (error) {

      forgeSvc.logout(req.session)

      res.status(error.statusCode || 404)
      res.json(error)
    }
  })

  return router
}

只需加载此 URL:“https://accounts.autodesk.com/Authentication/LogOut” 这将注销之前的用户会话,新用户可以登录。

更多详情请参考:https://forge.autodesk.com/blog/log-out-forge