passport-alipay.js 2.54 KB
/**
 * passport.js 支付宝登录插件
 *
 * @author JiangFeng<jeff.jiang@yoho.cn>
 * @date 2016/06/21
 */

'use strict';
const util = require('util');
const _ = require('lodash');
const md5 = require('md5');
const Strategy = require('passport-strategy');

// 支付宝网关地址
const ALIPAY_URL = 'https://mapi.alipay.com/gateway.do';

const defaultOptions = {
    service: 'alipay.auth.authorize',
    _input_charset: 'utf-8',   // esline-disable-line
    sign_type: 'MD5',
    target_service: 'user.auth.quick.login'
};

/**
 * 将参数排序,拼接成 "参数=参数值" 的格式
 *
 * @param {Object} params
 */
function paramsToRaw(params) {
    let keys = Object.keys(params);

    keys = keys.sort();
    let newArgs = {};

    keys.forEach((key) => {
        newArgs[key] = params[key];
    });

    let string = '';

    for (let k of newArgs) {
        string += '&' + k + '=' + newArgs[k];
    }
    string = string.substr(1);
    return string;
}

function AlipayStrategy(options) {
    Strategy.call(this);
    this.name = 'alipay';
    this._passReqToCallback = options.passReqToCallback;
}

util.inherits(AlipayStrategy, Strategy);

AlipayStrategy.prototype.authenticate = (req, options) => {
    if (req.query && req.query.is_success && req.query.sign && req.query.sign_type) {

        // sign check

        let query = req.query;
        let sign = query.sign;
        let signType = query.sign_type;

        delete query.sign_type;
        delete query.sign;
        let signString = paramsToRaw(query) + options.key;

        if (signType === 'MD5' && sign !== md5(signString)) {
            this.error('alipay callback sign check fail');
            this.fail('alipay callback sign check fail');
            return;
        }

        if (req.query.is_success === 'T') {
            let user = {
                userId: req.query.user_id,
                realName: req.query.realName,
                email: req.query.email
            };

            this.success(user, null);
        } else {
            this.error('alipay login fail');
            this.fail(req.error_code);
        }
    } else {
        let params = _.extends(defaultOptions, options);
        let signType = params.sign_type;

        delete params.sign_type;
        delete params.sign;
        let signString = paramsToRaw(params) + options.key;

        if (signType === 'MD5') {
            params.sign = md5(signString);
            params.sign_type = 'MD5';
        }

        this.redirect(ALIPAY_URL + '?' + paramsToRaw(params));
    }
};

module.exports.Strategy = AlipayStrategy;