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
用户使用他的 Autodesk 凭据登录
授权流程将用户重定向到`mycallback.com/callback/?code={{code}}
我的后端从 url 请求中获取 code
参数,并向 https://developer.api.autodesk.com/authentication/v1/gettoken
[ 发出 POST
请求=74=]
请求 returns,除其他外,access_token
我将 access_token
存储到用户的 session,并使用它向 API 发出下一个请求。
至此,一切如我所愿。现在我想注销用户,并可能以其他用户身份登录。
我服务器上的一个 /logout 端点清除了用户 session,删除了存储的 access_token。
一旦后端意识到没有活动 session/access_token,它会将用户重定向到身份验证流程(上面的步骤 #1)。
此时,我本以为会看到另一个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”
这将注销之前的用户会话,新用户可以登录。
我有 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
用户使用他的 Autodesk 凭据登录
授权流程将用户重定向到`mycallback.com/callback/?code={{code}}
我的后端从 url 请求中获取
[ 发出code
参数,并向https://developer.api.autodesk.com/authentication/v1/gettoken
POST
请求=74=]请求 returns,除其他外,
access_token
我将
access_token
存储到用户的 session,并使用它向 API 发出下一个请求。
至此,一切如我所愿。现在我想注销用户,并可能以其他用户身份登录。
我服务器上的一个 /logout 端点清除了用户 session,删除了存储的 access_token。
一旦后端意识到没有活动 session/access_token,它会将用户重定向到身份验证流程(上面的步骤 #1)。
此时,我本以为会看到另一个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” 这将注销之前的用户会话,新用户可以登录。