Authored by 陈峰

Merge branch 'feature/sessionKey' into 'gray'

Feature/session key



See merge request !21
... ... @@ -305,7 +305,7 @@ const bindMobile = (req, res, next) => {
sourceType: sourceType + '_bind'
});
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res, result.data.session_key).then(() => {
return { code: 200, message: result.message, data: { refer: refer } };
});
} else {
... ... @@ -339,7 +339,7 @@ const relateMobile = (req, res, next) => {
sourceType: sourceType + '_bind'
});
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res, result.data.session_key).then(() => {
req.session.thirdBind = '';
return { code: 200, message: result.message, data: { refer: refer } };
});
... ...
... ... @@ -54,7 +54,7 @@ const _doPassportCallback = (req, res, user) => {
refer: refer
});
} else if (result.code === 200 && result.data.uid) {
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res, result.data.session_key).then(() => {
return refer;
});
}
... ... @@ -201,7 +201,7 @@ const local = {
refer = !BlockRedirectFilter.test(decodeURI(refer)) && refer ? decodeURI(refer) : config.siteUrl;
yield LoginService.syncUserSession(user.uid, req, res).then(() => {
yield LoginService.syncUserSession(user.uid, req, res, user.session_key).then(() => {
res.json({
code: 200,
data: {
... ...
... ... @@ -268,7 +268,7 @@ let mobileRegister = (req, res, next) => {
return res.json(data);
}
return LoginService.syncUserSession(regResult.data.uid, req, res).then(() => {
return LoginService.syncUserSession(regResult.data.uid, req, res, regResult.data.session_key).then(() => {
return res.json({
code: 200,
message: '注册成功',
... ...
... ... @@ -13,6 +13,7 @@ const crypto = global.yoho.crypto;
const api = require('./login-api');
const UserService = require('./user-service');
const authcode = require('../../../utils/authcode');
const signin = (type, area, profile, password, shoppingKey, req) => {
let loginBy = {
... ... @@ -41,8 +42,23 @@ const signinByOpenIDAsync = (nickname, openId, sourceType, shoppingKey, unionId)
/**
* 同步用户信息到session
*/
const syncUserSession = (uid, req, res) => {
return UserService.profileAsync(uid).then((userInfo) => {
const syncUserSession = (uid, req, res, sessionKey) => {
let userId = {
toString: () => {
return uid;
}
};
if (sessionKey) {
req.session.SESSION_KEY = sessionKey;
res.cookie('_SESSION_KEY', authcode(sessionKey, '_SESSION_KEY', 2592000000, 'encode'), {
domain: 'yohobuy.com',
expires: new Date(Date.now() + 2592000000) // 有效期一年
});
userId.sessionKey = sessionKey;
}
return UserService.profileAsync(userId).then((userInfo) => {
let token = sign.makeToken(uid);
let user = userInfo.data;
let name = user.nickname || user.profile_name || user.username;
... ...
... ... @@ -11,7 +11,7 @@ const isTest = process.env.NODE_ENV === 'test';
module.exports = {
app: 'web',
appVersion: '5.5.2', // 调用api接口版本
appVersion: '5.6', // 调用api接口版本
port: 6003,
siteUrl: '//www.yohoblk.com',
signExtend: {
... ...
... ... @@ -8,6 +8,7 @@
const headerModel = require('../models/header');
const logger = global.yoho.logger;
const helpers = global.yoho.helpers;
/**
* 404 错误
... ... @@ -37,6 +38,17 @@ exports.notFound = () => {
*/
exports.serverError = () => {
return (err, req, res, next) => {
if (err && err.code === 401) {
logger.error(`401 error info:client_type=${req.query.client_type},req.user=${JSON.stringify(req.user)},req.query=${JSON.stringify(req.query)},cookies=${JSON.stringify(req.cookies)}`); // eslint-disable-line
if (req.xhr) {
return res.status(401).json(err);
} else {
return res.redirect(helpers.urlFormat('/passport/login', {
refer: req.originalUrl
}));
}
}
logger.error(`error at path: ${req.url}`);
logger.error(err);
if (!res.headersSent) {
... ...
... ... @@ -5,6 +5,7 @@ const Fn = require('lodash/fp');
const cookie = global.yoho.cookie;
const cache = global.yoho.cache;
const LoginService = require('../../apps/passport/models/login-service');
const authcode = require('../../utils/authcode');
/**
* 已登录用户的信息,包括记住我功能。
... ... @@ -14,12 +15,25 @@ module.exports = () => {
// 从 SESSION 中获取到当前登录用户的 UID
if (req.session && _.isNumber(req.session._LOGIN_UID)) {
req.user.uid = req.session._LOGIN_UID;
req.user.uid = {
toString: () => {
return req.session._LOGIN_UID;
},
sessionKey: req.session.SESSION_KEY
};
}
// session 没有读取到的时候,从 cookie 读取 UID
if (!req.user.uid && req.cookies._UID) {
req.user.uid = cookie.getUid(req);
let sessionKey = req.cookies._SESSION_KEY &&
authcode(req.cookies._SESSION_KEY, '_SESSION_KEY', 2592000000);
req.user.uid = {
toString: () => {
return cookie.getUid(req);
},
sessionKey
};
}
if (req.cookies._UID) {
... ... @@ -52,7 +66,7 @@ module.exports = () => {
return Promise.reject(new Error(result.message));
}
return LoginService.syncUserSession(result.data.uid, req, res);
return LoginService.syncUserSession(result.data.uid, req, res, result.data.session_key);
}).then(()=> {
return res.redirect(req.originalUrl);
}).catch(next);
... ...
{
"name": "yoho-blk",
"version": "0.2.5",
"version": "0.2.6",
"private": true,
"description": "A New Yohoblk Project With Express",
"repository": {
... ... @@ -67,7 +67,7 @@
"xss": "^0.2.13",
"connect-memcached": "^0.2.0",
"yoho-express-session": "^2.0.0",
"yoho-node-lib": "0.2.17"
"yoho-node-lib": "0.2.22"
},
"devDependencies": {
"autoprefixer": "^6.3.6",
... ... @@ -117,6 +117,7 @@
"yoho-jquery-placeholder": "^2.3.1",
"yoho-jquery-qrcode": "0.0.3",
"yoho-json2": "^1.0.0",
"yoho-cookie": "^1.2.0",
"yoho-slider": "0.0.2"
}
}
\ No newline at end of file
... ...
/**
* 全局引用js
* @author: feng.chen<feng.chen@yoho.cn>
* @date: 2017/03/15
*/
const $ = require('yoho-jquery');
const cookie = require('yoho-cookie');
// 初始化
// 注册ajaxError处理服务端401状态
$(document).ajaxError((event, xhr) => {
if (xhr.status === 401) {
cookie.remove('_UID');
cookie.remove('_TOKEN');
window.location.href = '/passport/login';
}
});
... ...
... ... @@ -29,7 +29,8 @@ shelljs.ls(path.join(__dirname, '/js/**/*.page.js')).forEach((f) => {
'yoho-jquery-placeholder',
'yoho-jquery-qrcode',
'yoho-jquery-dotdotdot',
'xss'
'xss',
path.join(__dirname, '/js/global.js')
];
});
... ...
'use strict';
const md5 = require('md5');
const microtime = function() {
let unixtimeMs = new Date().getTime();
let sec = parseInt(unixtimeMs / 1000, 10);
return (unixtimeMs - (sec * 1000)) / 1000 + ' ' + sec;
};
const getTimestamp = function() {
let unixtimeMs = new Date().getTime();
return parseInt(unixtimeMs / 1000, 10);
};
module.exports = function(str, key, expiry, operation) {
operation = operation ? operation : 'decode';
key = key ? key : '';
expiry = expiry ? expiry : 0;
let tmpstr, tmp;
let ckeyLength = 4;
key = md5(key);
// 密匙a会参与加解密
let keya = md5(key.substr(0, 16));
// 密匙b会用来做数据完整性验证
let keyb = md5(key.substr(16, 16));
// 密匙c用于变化生成的密文
let keyc = operation === 'decode' ?
str.substr(0, ckeyLength) : md5(microtime()).substr(-ckeyLength);
// 参与运算的密匙
let cryptkey = keya + md5(keya + keyc);
let strbuf;
if (operation === 'decode') {
str = str.substr(ckeyLength);
strbuf = new Buffer(str, 'base64');
// string = b.toString();
} else {
expiry = expiry ? expiry + getTimestamp() : 0;
tmpstr = expiry.toString();
if (tmpstr.length >= 10) {
str = tmpstr.substr(0, 10) + md5(str + keyb).substr(0, 16) + str;
} else {
let count = 10 - tmpstr.length;
for (let i = 0; i < count; i++) {
tmpstr = '0' + tmpstr;
}
str = tmpstr + md5(str + keyb).substr(0, 16) + str;
}
strbuf = new Buffer(str);
}
let box = new Array(256);
let rndkey = [];
for (let i = 0; i < 256; i++) {
box[i] = i;
// 产生密匙簿
rndkey[i] = cryptkey.charCodeAt(i % cryptkey.length);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
for (let j = 0, i = 0; i < 256; i++) {
j = (j + box[i] + rndkey[i]) % 256;
tmp = box[i];
box[i] = box[j];
box[j] = tmp;
}
// 核心加解密部分
let s = '';
for (let a = 0, j = 0, i = 0; i < strbuf.length; i++) {
a = (a + 1) % 256;
j = (j + box[a]) % 256;
tmp = box[a];
box[a] = box[j];
box[j] = tmp;
// 从密匙簿得出密匙进行异或,再转成字符
// s += String.fromCharCode(string[i] ^ (box[(box[a] + box[j]) % 256]));
/* jshint -W016*/
strbuf[i] = strbuf[i] ^ (box[(box[a] + box[j]) % 256]);
}
if (operation === 'decode') {
s = strbuf.toString();
if ((s.substr(0, 10) === '0'.repeat(10) ||
s.substr(0, 10) - getTimestamp() > 0) &&
s.substr(10, 16) === md5(s.substr(26) + keyb).substr(0, 16)) {
s = s.substr(26);
} else {
s = '';
}
} else {
s = strbuf.toString('base64');
let regex = new RegExp('=', 'g');
s = s.replace(regex, '');
s = keyc + s;
}
return s;
};
... ...