GraphQL 中的社交身份验证

Posted

技术标签:

【中文标题】GraphQL 中的社交身份验证【英文标题】:Social authentication in GraphQL 【发布时间】:2019-09-20 23:17:09 【问题描述】:

我正在创建一个依赖 Express 和 GraphQL 的后端,它将为客户端应用程序(android 和 react)提供服务。

我一直在关注这个article,了解如何使用passport.js 在 GraphQL 中进行社交身份验证。

本文使用passport-google-token策略,基于Apollo-server,但我个人更喜欢使用express-graphql。

在将我的 android 应用设置为使用 google auth 并尝试将突变发送到服务器后,我收到此错误

Google info:   InternalOAuthError: failed to fetch user profile
    at E:\_Projects\myProject\myProject-backend\node_modules\passport-google-token\lib\passport-google-token\strategy.js:114:28
    at passBackControl (E:\_Projects\myProject\myProject-backend\node_modules\oauth\lib\oauth2.js:132:9)
    at IncomingMessage.<anonymous> (E:\_Projects\myProject\myProject-backend\node_modules\oauth\lib\oauth2.js:157:7)
    at IncomingMessage.emit (events.js:194:15)
    at endReadableNT (_stream_readable.js:1125:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
    name: 'InternalOAuthError',
        message: 'failed to fetch user profile',
        oauthError:
     statusCode: 401,
        data:
        '\n  "error": \n    "code": 401,\n    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",\n    "status": "UNAUTHENTICATED"\n  \n\n'  

我相信我通过的令牌可能没有到达它应该到达的地方,但我不知道如何解决。

我在https://oauth2.googleapis.com/tokeninfo?id_token=MyToken 测试了我的令牌,它们工作正常。

这是 app.js 中的 graphQL 配置

app.use('/graphql', graphqlHTTP((req, res) => (
    schema,
    graphiql: true,
    context: req, res
)));

这是谷歌身份验证突变

        googleAuth: 
            type: authPayLoad,
            args: token: type: new GraphQLNonNull(GraphQLString),
            async resolve(_, token, req, res) 
                req.body = 
                    ...req.body,
                    access_token: token,
                ;

                try 
                    const data, info = await authenticateGoogle(req, res);
                    console.log("Google data: ", data);

                    if (data) 
                        const user = await User.upsertGoogleUser(data);

                        if (user) 
                            return (
                                name: user.name,
                                username: user.username,
                                token: user.generateJWT(),
                            );
                        
                    

                    if (info) 
                        console.log("Google info: ", info);

                        switch (info.code) 
                            case 'ETIMEDOUT':
                                return (new Error('Failed to reach Google: Try Again'));
                            default:
                                return (new Error('something went wrong'));
                        
                    
                    return (Error('server error'));

                 catch (e) 
                    console.log("Error: ", e);
                    return e
                
            ,
        ,

这是我的身份验证控制器

const passport = require('passport');
const Strategy: GoogleTokenStrategy = require('passport-google-token');

// GOOGLE STRATEGY
const GoogleTokenStrategyCallback = (accessToken, refreshToken, profile, done) => done(null, 
    accessToken,
    refreshToken,
    profile,
);

passport.use(new GoogleTokenStrategy(
    clientID: 'MY_CLIET_ID',
    clientSecret: 'SERVER-SECRET'
, GoogleTokenStrategyCallback));

module.exports.authenticateGoogle = (req, res) => new Promise((resolve, reject) => 
    passport.authenticate('google-token', session: false, (err, data, info) => 
        if (err) reject(err);
        resolve(data, info);
    )(req, res);
);

我预计当客户端应用程序使用令牌作为 arg 提交突变时,请求将被发送到谷歌并返回用户数据。我该如何解决这个问题。

【问题讨论】:

【参考方案1】:

passport-google-token 已存档,对我来说似乎已弃用。你为什么不试试passport-token-google。 可以类似的方式使用。

passport.use(new GoogleStrategy(
        clientID: keys.google.oauthClientID,
        clientSecret: keys.google.oauthClientSecret
    ,
    function (accessToken, refreshToken, profile, done) 
        return done(null, 
            accessToken,
            refreshToken,
            profile,
        );
    
));

module.exports.authenticate = (req, res) => new Promise((resolve, reject) => 
    passport.authenticate('google-token', session: false, (err, data, info) => 
        if (err) reject(err);
        resolve(data, info);
    )(req, res);
);

希望这会有所帮助。

【讨论】:

以上是关于GraphQL 中的社交身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Relay 和 GraphQL 中的身份验证

Django中的Python社交身份验证,makemigrations检测到没有变化

graphql + apollo-server-express,如何处理 express authMiddleware 中的身份验证错误?

使用身份验证的 graphql 模式拼接

如何使用 graphql 和护照设置身份验证但仍使用 Playground

使用 Python 社交身份验证仅获取令牌