19

Pracuję nad aplikacją REST api, używając NodeJS. Do uwierzytelnienia postanowiłem użyć Passport. Chcę naprawdę RESTOWNEGO API. Oznacza to, że muszę używać tokenów zamiast sesji.Uwierzytelnianie za pomocą usługi Rode NodeJS przy użyciu sieci społecznościowej Passport i OAuth2 +

Chcę umożliwić użytkownikom logowanie przy użyciu nazwy użytkownika i hasła lub przy użyciu sieci społecznościowych, takich jak Facebook, Google i Twitter.

mogę zrobić własny serwer OAuth2.0 wydawania Access i Refresh tokens użyciu modułu oauth2orize. Teraz mogę zarejestrować nowego użytkownika, a następnie wydać tokeny. Śledziłem ten tutorial:

http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/

Weryfikacja użytkownika do trasy:

// api ------------------------------------------------------------------------------------ 
    app.get('/api/userInfo', 
     passport.authenticate('bearer', { session: false }), 
     function(req, res) { 
      // req.authInfo is set using the `info` argument supplied by 
      // `BearerStrategy`. It is typically used to indicate scope of the token, 
      // and used in access control checks. For illustrative purposes, this 
      // example simply returns the scope in the response. 
      res.json({ user_id: req.user.userId, name: req.user.username, scope: req.authInfo.scope }) 
     } 
    ); 

Wszystko to działa całkiem dobrze. Niestety nie wiem, jak wdrożyć uwierzytelnianie społeczne.

czytałem ten poradnik:

http://scotch.io/tutorials/javascript/easy-node-authentication-facebook 

Jednak w tym poradniku nie robią naprawdę REST API. W tym samouczku zaimplementowałem już schemat użytkownika, w którym tokeny dla użytkownika lokalnego są przechowywane w osobnych modelach.

// define the schema for our user model 
var userSchema = mongoose.Schema({ 
    local: { 
     username: { 
      type: String, 
      unique: true, 
      required: true 
     }, 
     hashedPassword: { 
      type: String, 
      required: true 
     }, 
     created: { 
      type: Date, 
      default: Date.now 
     } 
    }, 
    facebook: { 
     id: String, 
     token: String, 
     email: String, 
     name: String 
    }, 
    twitter: { 
     id: String, 
     token: String, 
     displayName: String, 
     username: String 
    }, 
    google: { 
     id: String, 
     token: String, 
     email: String, 
     name: String 
    } 
}); 

Ale jak mogę zweryfikować użytkownika?

passport.authenticate('bearer', { session: false }), 

ta sprawdza tylko okaziciela żeton przed moim db, ale w jaki sposób mogę sprawdzić znaki społeczne? Czy czegoś brakuje?

+0

można opracować w jaki sposób ostatecznie rozwiązać ten? Czy możesz zostawić swój uchwyt na Twitterze za dalszą korespondencję. Dzięki :) –

+0

i zamiast samouczka aleksandrov, dlaczego nie można użyć paszportu-oauth? http://passportjs.org/guide/oauth/ –

+0

Po co także wdrażać OAuth dla własnego serwera? dlaczego nie użyć paszportu lokalnego, a następnie wydać żetony według strategii na okaziciela? –

Odpowiedz

6

Używam logowania do Facebooka dla własnego API RESTful dla my Notepads app here. Uruchomiłem aplikację jako stronę, która będzie używana jako strona internetowa, ale nadal komunikacja po zalogowaniu będzie odbywała się za pośrednictwem interfejsu API.

Następnie zdecydowałem się utworzyć mobile version of the same app, który będzie korzystać z interfejsu API. Postanowiłem zrobić to w ten sposób: aplikacja mobilna loguje się przez Facebooka i wysyła do API identyfikator użytkownika facebook i token dostępu FB, API wywołuje API Facebooka, aby zweryfikować te parametry, a jeśli uda się zarejestrować nowego użytkownika (lub loguje się istniejący) w DB mojej aplikacji, tworzy niestandardowy token dla tego użytkownika i zwraca go do aplikacji mobilnej. Aplikacja mobilna wysyła ten niestandardowy token w celu uwierzytelnienia aplikacji za pomocą interfejsu API.

Oto niektóre kodu:

auth w API (używa modułu npm fbgraph):

var graph = require('fbgraph'), 
Promise = require('bluebird') 
... 
Promise.promisify(graph.get); 
... 
var postAuthHandler = function (req, res) { 
    var fbUserId = req.body.fbId, 
    fbAccessToken = req.body.fbAccessToken, 
    accessToken = req.body.accessToken; 
    ... 
    graph.setAppSecret(config.facebook.app.secret); 
    graph.setAccessToken(fbAccessToken); 

    var graphUser; 
    var p = graph.getAsync('me?fields=id,name,picture') 
     .then(function (fbGraphUser) { 
      //when the given fb id and token mismatch: 
      if (!fbGraphUser || fbGraphUser.id !== fbUserId) { 
       console.error("Invalid user from fbAccessToken!"); 
       res.status(HttpStatus.FORBIDDEN).json({}); 
       return p.cancel(); 
      } 

      graphUser = fbGraphUser; 

      return User.fb(fbUserId); 
     }) 
     .then(function (user) { 
      if (user) { 
       //user found by his FB access token 
       res.status(HttpStatus.OK).json({accessToken: user.accessToken}); 
       //stop the promises chain here 
       return p.cancel(); 
      } 
      ...create the user, generate a custom token and return it as above... 

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/6617a5cb418ba8acd6351ef9a9f69228f1047154/src/routes/users.js#L46.

Model użytkownika:

var userSchema = new mongoose.Schema({ 
    facebookId: { type: String, required: true, unique: true }, 
    accessToken: { type: String, required: true, unique: true }, 
    name: { type: String, required: true }, 
    photo: { type: String, required: true }, 
    categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }], 
    notepads: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Notepad' }] 
}); 

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/master/src/models/user.js#L9.

Facebook auth w aplikacji mobilnej:

   auth: function(fbId, fbAccessToken) { 
       return $http({ 
        url: apiBase + '/users/auth', 
        data: { 
         fbId: fbId, 
         fbAccessToken: fbAccessToken 
        }, 
        method: 'POST', 
        cache: false 
       }); 
      }, 
      ... 

https://github.com/iliyan-trifonov/notepads-ionic/blob/master/www/js/services.js#L33.

Aplikacja mobilna wysyła token z prośbą:

notepads: { 
      list: function() { 
       return $http({ 
        url: apiBase + '/notepads?insidecats=1' + '&token=' + User.get().accessToken/*gets the token from the local storage*/, 
        method: 'GET', 
        cache: false 
       }); 
      }, 

Jest to/kątowe/app Ionic Cordova. Logowanie do Facebooka z aplikacji mobilnej powoduje uruchomienie aplikacji Facebook zainstalowanej na Twoim telefonie lub otwarcie wyskakującego okienka do logowania na Facebooku. Następnie wywołanie zwrotne zwraca identyfikator użytkownika Facebooka i token dostępu do mojej aplikacji mobilnej.

fbgraph moduł npm: https://github.com/criso/fbgraph

+0

Po prostu sformatuj adresy URL i będą one aktywne. Do tego nie są wymagane żadne uprawnienia. –

+0

Dzięki, @NickVolynkin! Wczoraj udało mi się aktywować tylko dwa pierwsze 2 adresy i otrzymałem powiadomienie, że potrzebuję co najmniej 10 powtórzeń. dla reszty. Ale dziś mam go i pomyślnie sformatowałem adresy URL. –

0

Strategie dotyczące mediów społecznościowych dotyczące paszportu zależą od sesji. Nie będą działać bez niego.

Używam tego samego problemu Chciałem, aby mój serwer REST był bezpaństwowy.

Moim zdaniem są 2 opcje.

  1. Dodaj sesje z serwerem spoczynku
  2. Dodaj nowy serwer uwierzytelniający, który jest odpowiedzialny za tworzenie i rozdawanie żeton.

PS: Powinieneś oznaczyć to jako paszport, aby mógł go zobaczyć programista portowy.

+0

Zamiast samouczka aleksandrov (http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/) dlaczego nie można użyć paszportu-oauth? http://passportjs.org/guide/oauth/ –

+0

To jest moduł, którego samouczek używa pod maską. To ten, który korzysta z sesji. Tokeny są przechowywane w sesji tak, że gdy przekierowania przeglądarki mogą wiązać użytkownika/token, który jest zwracany. Moja autoryzacja jest z tego powodu stanowa, a mój api jest bezpaństwowcem. –

2

Iv'e stworzony na następujący schemat:

var userSchema = mongoose.Schema({ 
    local: { 
     username: String, 
     password: String 
    }, 
    facebook: { 
     id: String, 
     token: String, 
     email: String, 
     name: String 
    }, 
    google: { 
     id: String, 
     token: String, 
     email: String, 
     name: String 
    }, 
    token: { 
     type: Schema.Types.ObjectId, 
     ref: 'Token', 
     default: null 
    } 
}); 

var tokenSchema = mongoose.Schema({ 
    value: String, 
    user: { 
     type: Schema.Types.ObjectId, 
     ref: 'User' 
    }, 
    expireAt: { 
     type: Date, 
     expires: 60, 
     default: Date.now 
    } 
}); 

Po zalogowaniu się do mojej aplikacji internetowej, używam plugin PassportJS społecznościowych takich jak Facebook/Google. Przykład:

//auth.js(router) 
router.get('/facebook', passport.authenticate('facebook', {scope: ['email']})); 

router.get('/facebook/callback', 
    passport.authenticate('facebook', { successRedirect: '/profile', 
             failureRedirect: '/' })); 

Teraz, gdy chcę nawigować po aplikacji internetowej, używam uwierzytelniania sesji, które zostało mi udostępnione przez wtyczkę Facebooka. Gdy użytkownik chce zażądać tokena API, musi być zalogowany, aby móc skojarzyć ten token z użytkownikiem.

Teraz użytkownik ma skojarzony z nim token, którego może używać do uwierzytelniania tokenów dla mojego interfejsu API.

Moje trasy API nie obchodzą ani nie patrzą na sesje, wszystko, na czym im zależy, to token. Dokonaliśmy tego, tworząc router ekspresowy i stosując strategię przenoszenia paszportów jako oprogramowanie pośrednie dla wszystkich tras zmierzających w stronę mojego interfejsu API.

//api.js (router) 
//router middleware to use TOKEN authentication on every API request 
router.use(passport.authenticate('bearer', { session: false })); 

router.get('/testAPI', function(req, res){ 
     res.json({ SecretData: 'abc123' }); 
    }); 

Więc teraz używam tylko uwierzytelnianie tokena dla mojego API (Nie kiedykolwiek spojrzeć na danych sesyjnych) i uwierzytelnianie sesji, aby łatwo poruszać się po webapp. Przykładem użycia sesji do nawigacji po aplikacji jest:

//secure.js(router) - Access private but NON-API routes. 
//router middleware, uses session authentication for every request 
router.use(function(req, res, next){ 
     if(req.isAuthenticated()){ 
      return next(); 
     } 
     res.redirect('/auth'); 
    }); 
//example router 
router.get('/profile', function(req, res){ 
     res.send("Private Profile data"); 
    }); 

Mamy nadzieję, że to pomoże!

+2

Jeszcze raz dziękuję! Tak, zrozumiałem twoją koncepcję. Jednak to nie sprawia, że ​​backend jest całkowicie URUCHOMIONY - nie ma punktu wejścia dla facebookowego auth, powiedzmy urządzenia z Androidem. Powinien to być mechanizm RESTULT. Po tym rozwiązanie jest idealne, ponieważ tokeny nośnika przejmują w celu wygenerowania określonych tokenów aplikacji. dlatego zostawiłem tę myśl w Twoim filmie https://www.youtube.com/watch?v=VVFedQZgUgw –

0

jeśli używasz tokena na okaziciela, wszystko co musisz zrobić, to przekazać unikalny identyfikator do użytkownika interfejsu API. Najprawdopodobniej zostanie to wykonane w pojedynczej rozmowie, może w formie logowania. Następnie każde wywołanie interfejsu API wymaga tego tokena, który weryfikuje token w bazie danych i aktualizuje jego wartość Time To Live. Nie potrzebujesz pojedynczych tokenów w swoim schemacie dla każdego logowania potrzebujesz indywidualnego schematu dla tokenów, który ma wartość TTL (Time To Live Value)

Powiązane problemy