簡體   English   中英

Passport.js / Google OAuth2 策略 - 如何在登錄時使用令牌進行 API 訪問

[英]Passport.js / Google OAuth2 strategy - How to use token on login for API access

我正在使用passport.js 通過他們的域Google 帳戶登錄用戶。 這很好用,但現在我需要讓這個應用程序訪問一些谷歌 API(驅動器、工作表等)。

當用戶登錄時,日志中會出現一條消息,這使得護照似乎具有所有必需的信息:

info: [06/Jun/2019:21:24:37 +0000] "302 GET /auth/callback?code=** USER ACCESS TOKEN HERE **&scope=email%20profile%20https://www.googleapis.com/auth/drive.file%20https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/drive HTTP/1.1" [46]

這是通過通過passport.authenticate() 傳遞附加范圍來實現的,它向用戶顯示“授予此應用程序訪問您的Google 帳戶上的這些內容的權限?” 屏幕 :

//Initial auth call to Google
router.get('/',
  passport.authenticate('google', {
    hd: 'edmonds.wednet.edu',
    scope: [
      'email',
      'profile',
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/drive.file',
      'https://www.googleapis.com/auth/spreadsheets'
    ],
    prompt: 'select_account'
  })
);

但是,當我嘗試使用以下內容調用 API 時:

const {google} = require('googleapis');
const sheets = google.sheets({version: 'v4', auth});

router.post('/gsCreate', function(req,res,next){

  sheets.spreadsheets.create({
    // Details here.....
  });

});

我只得到錯誤(當前是debug: authClient.request is not a function

我的問題是:我是否可以使用這樣的設置,要求用戶登錄並授予一次權限,然后以某種方式通過護照將其保存到他們的用戶會話中?

我有同樣的問題,但通過使用以下過程指定“范圍”,我能夠訪問 Google Gmail API 功能以及 Passport.js 用戶身份驗證。 首先,創建一個文件來在 nodejs 中設置passport-google-strategy,如下所示。

passport_setup.js

const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20')
const fs = require("fs");
const path = require('path');
//make OAuth2 Credentials file using Google Developer console and download it(credentials.json)
//replace the 'web' using 'installed' in the file downloaded
var pathToJson = path.resolve(__dirname, './credentials.json');
const config = JSON.parse(fs.readFileSync(pathToJson));


passport.serializeUser((user, done) => {
    done(null, user.id)
})

passport.deserializeUser((id, done) => {

    const query = { _id: id }
    Users.findOne(query, (err, user) => {
        if (err) {
            res.status(500).json(err);
        } else {
            done(null, user)
        }
    })
})

//create a google startergy including following details
passport.use(
    new GoogleStrategy({
        clientID: config.installed.client_id,
        clientSecret: config.installed.client_secret,
        callbackURL: config.installed.redirect_uris[0]
    }, (accessToken, refreshToken,otherTokenDetails, user, done) => {
        
        //in here you can access all token details to given API scope
        //and i have created file from that details
        let tokens = {
            access_token: accessToken,
            refresh_token: refreshToken,
            scope: otherTokenDetails.scope,
            token_type: otherTokenDetails.token_type,
            expiry_date:otherTokenDetails.expires_in
        }
        let data = JSON.stringify(tokens);
        fs.writeFileSync('./tokens.json', data);


        //you will get a "user" object which will include the google id, name details, 
        //email etc, using that details you can do persist user data in your DB or can check 
        //whether the user already exists

        //after persisting user data to a DB call done
        //better to use your DB user objects in the done method

        done(null, user)
  
    })
)

然后在 nodejs 中創建 index.js 文件用於 API 路由管理並調用 Gmail API 的發送方法。 另外,運行以下命令來安裝“google-apis”

npm install googleapis@39 --save

索引.js

const express = require("express")
//import passport_setup.js
const passportSetup = require('./passport_setup')
const cookieSeesion = require('cookie-session');
const passport = require("passport");
//import google api
const { google } = require('googleapis');
//read credentials file you obtained from google developer console
const fs = require("fs");
const path = require('path');
var pathToJson_1 = path.resolve(__dirname, './credentials.json');
const credentials = JSON.parse(fs.readFileSync(pathToJson_1));


//get Express functionalities to app
const app = express();

// **Middleware Operations**//

//cookie encryption
app.use(cookieSeesion({
    name:'Reserve It',
    maxAge: 1*60*60*1000,
    keys: ['ranmalc6h12o6dewage']
}))

//initialize passort session handling
app.use(passport.initialize())
app.use(passport.session())

app.use(express.json());    

//**API urls**//

//route to authenticate users using google by calling google stratergy in passport_setup.js 
//mention access levels of API you want in the scope
app.get("/google", passport.authenticate('google', {
scope: ['profile',
    'email',
    'https://mail.google.com/'
],
accessType: 'offline',
prompt: 'consent'
}))

//redirected route after obtaining 'code' from user authentication with API scopes
app.get("/google/redirect", passport.authenticate('google'), (req, res) => {

    try {
        //read token file you saved earlier in passport_setup.js
        var pathToJson_2 = path.resolve(__dirname, './tokens.json');
        //get tokens to details to object
        const tokens = JSON.parse(fs.readFileSync(pathToJson_2));
        //extract credential details
        const { client_secret, client_id, redirect_uris } = credentials.installed

        //make OAuth2 object
        const oAuth2Client = new google.auth.OAuth2(client_id,
        client_secret,
        redirect_uris[0])

        // set token details to OAuth2 object
        oAuth2Client.setCredentials(tokens)
     
       //create gmail object to call APIs
       const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })

       //call gmail APIs message send method
       gmail.users.messages.send({
             userId: 'me',//'me' indicate current logged in user id
             resource: {
                raw: //<email content>
               }
        }, (err, res) => {
            if (err) {
              console.log('The API returned an error: ' + err)
              throw err
            }
            console.log('Email Status : ' + res.status)
            console.log('Email Status Text : ' + res.statusText)
         })

        res.status(200).json({ status:true })
        
    } catch (err) {
        res.status(500).json(err)
    }

})

app.listen(3000, () => { console.log('Server Satrted at port 3000') })

為了清楚起見,您可以使用express.Router()將 index.js 文件中的路由分隔到不同的文件

如果您想調用另一個 Google API 服務,只需更改此代碼段和其下方的代碼;

   const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
   gmail.users.messages.send(....Send Method internal implementation given above....)

對於 Google 雲端硬盤:

const drive = google.drive({version: 'v3', auth: oAuth2Client});
drive.files.list(...Refer "Google Drive API" documentation for more details....)

我相信您不能將passport.js 用於Sheets 或Drive 等API 的三足oauth。

請查看 Using OAuth for web servers 文檔

user835611 有正確的答案,因為該頁面很好地解釋了所有內容。 但是,如果您仍然需要更多,下面的鏈接確實幫助我了解它是如何工作的。

https://github.com/googleapis/google-auth-library-nodejs#oauth2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM