0

想象一下,我正在api .example.com 上实现一个 API 服务,该服务需要使用 OAuth2 以足够的粒度来保护其端点,以适应不同的用户类型。

  • 针对 Facebook 进行身份验证的用户只能访问 https:// api .example.com/facebook
  • 对Twitter进行身份验证的用户只能访问 https://api.example.com/twitter
  • 针对授权服务进行本地身份验证的用户可以访问 facebook 和 twitter 端点

这意味着我们有以下角色:

  • 身份验证提供程序(授权服务器、Facebook、Twitter)
  • 授权提供程序(我的 OAuth2 服务器)(auth .example.com)
  • 资源提供者(我的 API 服务器)(api .example.com)
  • ExpressJS webapp 或 SPA ( www .example.com) 或本机应用程序

问题:

Q1应用流程应该如何实现?

我的想法是...

webapp 必须在 session 中将 accessToken 存储到api .example.com,并将 sessionid 发送到 Web 浏览器。如果没有accessToken,则必须将浏览器重定向到auth.example.com/login/selectprovider/ 提供client_id=" www.example.com "和client_secret ,redirect_url="https://www.example.com /”。

在 https:// auth .example.com/login/selectprovider/ 上,用户选择 facebook 或 twitter 或本地,并且auth .example.com 使用 client_id 和 client_secret 将用户(再次)重定向到 /login 或 facebook 或 twitter 和redirect_url=https:// auth .example.com/ twitter或 https:// auth .example.com/ twitter以轻松区分三者。

Facebook/twitter/local 方法将对用户进行身份验证并将浏览器重定向回auth .example.com。

然后auth .example.com 将为api .example.com 生成一个(承载)accessToken 并将其与 user.id 一起存储到本地数据库表中,并具有关联的范围(“facebook”、“twitter”或“local”) ,将密钥(userId)放入浏览器会话并重定向到https://www.example.com/

现在,当用户单击 WebApp 中的链接时,www .example.com 会在api .example.com上执行 GET 或 POST ,提供 client_id="www.example.com" client_secret 和 access_token。

api .example.com 端点验证 accessToken,如果没问题,则执行 API 并将值返回给www .example.com,然后将其呈现给用户的浏览器。

Q2以上是正确的流程,还是有更好的方法?如果正确,api .example.com 如何在其端点验证 accessToken?

auth .example.com是否应该为此公开一个只能使用 client_id=" api .example.com" 和 client_secret 访问的特殊端点(例如 /userinfo)?每次调用似乎都很昂贵,但是api .example.com还能如何信任令牌的有效性(因为它已过期或用户已注销)?

什么是符合 OAuth2 标准的方式?

Q3在护照/OAuth2orize 示例中,我看到了验证身份验证的 3 种方式:

  • if (req.user) {...};
  • if (req.isAuthenticated()) {...};
  • passport.authenticate('bearer', {session: false);

Q4 passport.authenticate('facebook') 到底是做什么的?

该信息在策略中提供。

passport.use(new FacebookStrategy({
    clientID: FACEBOOK_APP_ID,
    clientSecret: FACEBOOK_APP_SECRET,
    callbackURL: "http://localhost:3000/auth/facebook/callback"
  },
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ facebookId: profile.id }, function (err, user) {
        return cb(err, user);
    });
  }
));

所以这包含了client_id 和client_secret。这个什么时候用?每次调用passport.authenticate('facebook')?是否将整个重定向到 facebook 登录页面,获得授权代码授予并将其交换为 accessToken,以某种方式在内部存储 accessToken 并保留它直到注销?

这似乎不太可能,但我看不出它如何在没有这一切的情况下实际验证用户。而且每次 API 调用都太昂贵了,所以我相信它会更有效地工作。但我不知道如何和研究源代码并没有让它更清楚。

Q5 *api**.example.com 如何知道每个 API 请求中www .example.com 所包含的 Bearer accessToken 没有伪造或过期?

我认为它必须根据auth .example.com 服务对其进行检查,而该服务又必须检查 facebook/twitter 会话是否仍然有效,并在那一刻使用 refreshToken 刷新令牌?

4

0 回答 0