Xác thực đăng nhập bằng Passport – Twitter

Bài viết này là một phần của series bài viết Xác thực đăng nhập bằng Passport:

  1. Bắt đầu với Local Authentication
  2. Facebook
  3. Twitter (Bạn đang ở đây)
  4. Google
  5. Liên kết các tài khoản

Chào mừng tới phần 3 của series Xác thực đăng nhập bằng Passport. Chúng ta sẽ sử dụng nền tảng của ứng dụng chúng ta đã xây dựng từ những bài trước để thêm tính năng xác thực với Facebook. Chúng ta đã một cấu trúc chương trình đầy đủ với các gói thư viện cần dùng, user model, cấu hình ứng dụng và các views.

Chúng ta đã tạo ra một chương trình với cấu trúc khá rõ ràng và ngắn gọn, ở bài này những gì chúng ta phải làm sẽ là tạo một Twitter app, sửa các file sau:

Lưa thông tin cấu hình Twitter app: AppId, Secret config/auth.js
Cấu hình Twitter Strategy cho Passport config/passport.js
Khởi tạo route app/routes.js
Cập nhật view views/

Trong bài không nó rõ các bước tạo một App Twitter, tôi mặc định các bạn đã làm được bước này. Chúng ta sẽ đi thẳng tới việc cấu hình Passport Twitter Strategy.

Xác thực với Twitter sử dụng Passport

Tạo ứng dụng Twitter

Tiến hành khởi tạo một ứng dụng Twitter tại đường dẫn Twitter Developers. Mình nghĩ việc này không quá phức tạp. Chúng ta sẽ cần các thông tin consumer key, consumer secret, và callback URL.

Callback URL: Ứng dụng của chúng ta sử dụng đường dẫn http://localhost:8080/auth/twitter/callback nhưng Twitter không chấp nhận địa chỉ tên miền là localhost, nên chúng ta phải đăng ký callback url là http://127.0.0.1:8080/auth/twitter/callback .

Giờ thêm thông tin về consumer key và consumer secret vào file auth.js để sử dụng cho việc xác thực với Twitter

// config/auth.js

module.exports = {

    'facebookAuth': {
        'clientID': '182734854751xxxx', // App ID của bản
        'clientSecret': '7e7b945a5df7c7da047ee5577058xxxx', // App Secret của bạn
        'callbackURL': 'http://localhost:8080/auth/facebook/callback'
    },

    'twitterAuth': {
        'consumerKey': 'ieCPgRLTTijLBvHwQs40xxxx',
        'consumerSecret': 'IY0bJrhRU9Pn4Rqf8AtDP7iclsSoEHW62OL7f2oln6vLCgxxxx',
        'callbackURL': 'http://localhost:8080/auth/twitter/callback'
    },

    'googleAuth': {
        'clientID': 'your-secret-clientID-here',
        'clientSecret': 'your-client-secret-here',
        'callbackURL': 'http://localhost:8080/auth/google/callback'
    }

};

Cấu hình Twitter Strategy cho Passport config/passport.js

Giờ để ứng dụng của chúng ta có thể sử dụng xác thực của Twitter, chúng ta sẽ phải cấu hình Twitter Strategy. Strategy này sẽ sử dụng xác thực của Twitter và xử lý dữ liệu khi xác thực Twitter thành công.

Chúng ta đã có code cho Local Strategy và Facebook Strategy ở file này, chúng ta sẽ thêm phần Twitter Strategy ở ngay bên dưới.

// config/passport.js

// load những thứ chúng ta cần
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;

// Lấy thông tin những giá trị auth
var configAuth = require('./auth');

// load  user model
var User = require('../app/models/user');

module.exports = function (passport) {

    // =========================================================================
    // passport session setup ==================================================
    // =========================================================================
    // required for persistent login sessions
    // passport needs ability to serialize and unserialize users out of session

    // used to serialize the user for the session
    passport.serializeUser(function (user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function (id, done) {
        User.findById(id, function (err, user) {
            done(err, user);
        });
    });

    // code for login (use('local-login', new LocalStategy))
    // code for signup (use('local-signup', new LocalStategy))
    // code for facebook (use('facebook', new FacebookStrategy))

    // =========================================================================
    // TWITTER =================================================================
    // =========================================================================
    passport.use(new TwitterStrategy({
            consumerKey: configAuth.twitterAuth.consumerKey,
            consumerSecret: configAuth.twitterAuth.consumerSecret,
            callbackURL: configAuth.twitterAuth.callbackURL
        },
        function (token, tokenSecret, profile, done) {
            process.nextTick(function () {
                // tìm trong db xem có user nào đã sử dụng twitter id này chưa
                User.findOne({'twitter.id': profile.id}, function (err, user) {
                    if (err)
                        return done(err);

                    // Nếu tìm thấy user, cho họ đăng nhập
                    if (user) {
                        return done(null, user); // user found, return that user
                    } else {
                        // nếu chưa có, tạo mới user
                        var newUser = new User();

                        // lưu các thông tin cho user
                        newUser.twitter.id = profile.id;
                        newUser.twitter.token = token;
                        newUser.twitter.username = profile.username;
                        newUser.twitter.displayName = profile.displayName;

                        // lưu vào db
                        newUser.save(function (err) {
                            if (err)
                                throw err;
                            // nếu thành công, trả lại user
                            return done(null, newUser);
                        });
                    }
                });

            });

        }));

};

Profile: Object chứ thông tin user của dịch vụ(Facebook, Twitter, Google) sẽ có cấu trúc thông tin khác nhau, nhưng Passport đã xử lý về một đối tượng để dễ xử lý user profile doc.

Chúng ta sẽ sử dụng Strategy cho việc xác thực với Twitter và xử lý khi Twitter trả lại thông tin. Chúng ta sẽ lưu thông tin user và chuỗi token để truy cập các dịch vụ của Twitter.

Theo kinh nghiệm của tôi, khi sử dụng Passport với Twitter chúng ta nhận được những thông tin khác nhau. Thông tin cơ bản nhất được Twitter trả lại trông giống thế này:

{
    id: '1306682xx',
    username: 'hoangxxx',
    displayName: 'Hoang Dinh',
    photos: [{ value: 'https://pbs.twimg.com/profile_images/805686xxx/IMG_0075_normal.JPG' }]
}

Thông tin email: Bạn có thể hỏi tôi sao không thể lấy thông email của tài khoản Twitter. Trong hệ thống của Twitter, tài khoản không thực sự gắn với một email thực như trên Facebook và Google+.

Giờ chúng ta sẽ thiết lập các routes và hiển thị thông tin user ra profile page.

Routes app/routes.js

Giống như với Facebook, chúng ta sẽ cần 2 routes:

  • /auth/twitter: Gửi yêu cầu của chúng ta tời Twitter để yêu cầu xác thực.
  • /auth/twitter/callback: Twitter gửi lại ứng dụng của chúng ta chuỗi token và thông tin user.
// app/routes.js
...
    // =====================================
    // TWITTER ROUTES ======================
    // =====================================
    // yêu cầu xác thực bằng twitter
    app.get('/auth/twitter', passport.authenticate('twitter'));

    // xử lý sau khi user cho phép xác thực với twitter
    app.get('/auth/twitter/callback',
        passport.authenticate('twitter', {
            successRedirect: '/profile',
            failureRedirect: '/'
        }));
...

Routes của chúng ra rất đơn giản. Yêu cầu xác thực và xử lý callback.

Hiển thị thông tin user index.ejs, profile.ejs

Chúng ta đã có các routes, chúng ta chỉ cần cung cấp cho người dùng một cái nút để đăng nhập với Twitter. Tiếp theo, sau khi họ đã xác thực và được chuyên tới trang riêng tư – profile, chúng ta sẽ hiển thị thông tin của user ở đây.

Nút đăng nhập với Twitter

Chúng ta sẽ thêm nút đăng nhập với Twitter vào file views/index.ejs

<!-- views/index.ejs -->
...
        <a href="/auth/facebook" class="btn btn-primary"><span class="fa fa-facebook"></span> Facebook</a>
        <a href="/auth/twitter" class="btn btn-info"><span class="fa fa-twitter"></span> Twitter</a>
...

Chúng ta đã có nút để xác thực với Twitter. Khi user click vào nút đó, họ sẽ truy cập tới route /auth/twitter nơi họ sẽ được chuyển tới Twitter Strategy. Họ sẽ gửi tới Twitter một yêu cầu xác thực.

Nếu một user nhấn Cancel, họ sẽ được chuyển về trang chủ. Đó là cài đặt được đặt ở failureRedirect của route /auth/twitter/callback. Nếu việc xác thực thành công, thông tin user sẽ được lưu lại và họ được chuyển tới trang /profile .

Trang Profile views/profile.ejs

Cuối cùng chúng ta sẽ hiển thị thông tin user ở trang profile.

Chúng ta có thể thấy user ở trong db:

Giờ chúng ta hiển thị thông tin ra ngoài trang profile:

<!-- views/profile.ejs -->
...
        <!-- TWITTER INFORMATION -->
        <div class="col-sm-6">
            <div class="well">
                <h3 class="text-info"><span class="fa fa-twitter"></span> Twitter</h3>

                <p>
                    <strong>id</strong>: <%= user.twitter.id %><br>
                    <strong>token</strong>: <%= user.twitter.token %><br>
                    <strong>username</strong>: <%= user.twitter.username %><br>
                    <strong>displayName</strong>: <%= user.twitter.displayName %>
                </p>

            </div>
        </div>
...

Buzz!

Chúng ta đã hoàn thành việc cấu hình ứng dụng xác thực với Twitter: Cấu hình Passport cho Twitter, thêm routesm, xác thực với Twitter và  hiển thị thông tin profile của người dùng.

Bài viết tiếp theo chúng ta sẽ tiến hành xây dựng ứng dụng xác thực với Google.

Từ khóa: , ,