我有一个应用,我想使用第三方API(例如Google,Facebook等)登录。客户端前端只是一个与我的服务器交互的JavaScript SPA。服务器本质上只需要存储第三方ClientID
和ClientSecret
。
要登录,客户端会将用户链接到MyAPI/login
。然后,MyAPI会将用户重定向到第三方登录页面以及ClientID
。验证后,第三方会将用户重定向回MyAPI/callback
code
查询参数。 MyAPI会将此code
与ClientID
和ClientSecret
一起发送回第三方API。第三方API最终会返回access_token
和refresh_token
。
我的问题是我应该如何将令牌发送回客户端应用程序?而且,一旦客户有代币,我该如何存储它们?
答案 0 :(得分:2)
您所描述的是OAuth的授权代码授权流程。在Auth Code流程中,会向客户端提供一个代码(在本例中为MyAPI),以便用户永远不会收到access_token
或refresh_token
,因此不必信任它们。< / p>
通过向用户提供这些令牌并允许它们将其存储在本地存储中,您正在规避Auth Code流的安全性优势。绝对不建议这样做,除非安全性对您来说不是一个大问题(您信任该用户)。
正如评论所示,您可以使用Cookie来保持与MyAPI的会话。但是,access_token
和refresh_token
应保留在会话数据中,而不是直接与用户共享。这强制了只有MyAPI代表用户才能访问第三方API。
在此问题的接受答案中提供了对验证码流程的更好解释:What is the difference between the 2 workflows? When to use Authorization Code flow?
MyAPI的一个不完整的Express.js示例:
// imports
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const jwt = require('jsonwebtoken');
// setup passport (an authentication middleware) and use it with the session provided by express-session
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((obj, done) => {
done(null, obj);
});
passport.use(new SomeStrategy(...strategyOptions));
const app = express();
app.use(passport.initialize());
app.use(passport.session());
// route handlers
app.get('/login', passport.authenticate('SOME_STRATEGY'), () => {});
app.get('/callback', passport.authenticate('SOME_STRATEGY'), { failureRedirect: '/badlogin' }, (req, res) => res.send(200));
app.get('/resource', (req, res) => {
const accessToken = req.user.access_token; // req.user has the session information including the access token
try {
// verify the access token with the 3rd party auth's public key (NOT THE SAME AS DECODING IT!)
const decodedAccessToken = jwt.verify(accessToken, thirdPartAuthPublicKey);
return res.send(200).send(decodedAccessToken);
} catch (err) {
return res.send(401).send('unauthenticated');
}
});
此处,服务器将access_token
保留在用户的会话数据(req.user
)中。当用户请求资源时,服务器会尝试验证access_token
并返回其解码内容。