const {
|
findUser
|
} = require('./account')
|
const {
|
userCollection,
|
LOG_TYPE
|
} = require('../../common/constants')
|
const {
|
ERROR
|
} = require('../../common/error')
|
const {
|
logout
|
} = require('./logout')
|
const PasswordUtils = require('./password')
|
|
async function realPreLogin (params = {}) {
|
const {
|
user
|
} = params
|
const appId = this.getUniversalClientInfo().appId
|
const {
|
total,
|
userMatched
|
} = await findUser({
|
userQuery: user,
|
authorizedApp: appId
|
})
|
if (userMatched.length === 0) {
|
if (total > 0) {
|
throw {
|
errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP
|
}
|
}
|
throw {
|
errCode: ERROR.ACCOUNT_NOT_EXISTS
|
}
|
} else if (userMatched.length > 1) {
|
throw {
|
errCode: ERROR.ACCOUNT_CONFLICT
|
}
|
}
|
const userRecord = userMatched[0]
|
checkLoginUserRecord(userRecord)
|
return userRecord
|
}
|
|
async function preLogin (params = {}) {
|
const {
|
user
|
} = params
|
try {
|
const user = await realPreLogin.call(this, params)
|
return user
|
} catch (error) {
|
await this.middleware.uniIdLog({
|
success: false,
|
data: user,
|
type: LOG_TYPE.LOGIN
|
})
|
throw error
|
}
|
}
|
|
async function preLoginWithPassword (params = {}) {
|
const {
|
user,
|
password
|
} = params
|
try {
|
const userRecord = await realPreLogin.call(this, params)
|
const {
|
passwordErrorLimit,
|
passwordErrorRetryTime
|
} = this.config
|
const {
|
clientIP
|
} = this.getUniversalClientInfo()
|
// 根据ip地址,密码错误次数过多,锁定登录
|
let loginIPLimit = userRecord.login_ip_limit || []
|
// 清理无用记录
|
loginIPLimit = loginIPLimit.filter(item => item.last_error_time > Date.now() - passwordErrorRetryTime * 1000)
|
let currentIPLimit = loginIPLimit.find(item => item.ip === clientIP)
|
if (currentIPLimit && currentIPLimit.error_times >= passwordErrorLimit) {
|
throw {
|
errCode: ERROR.PASSWORD_ERROR_EXCEED_LIMIT
|
}
|
}
|
const passwordUtils = new PasswordUtils({
|
userRecord,
|
clientInfo: this.getUniversalClientInfo(),
|
passwordSecret: this.config.passwordSecret
|
})
|
|
const {
|
success: checkPasswordSuccess,
|
refreshPasswordInfo
|
} = passwordUtils.checkUserPassword({
|
password
|
})
|
if (!checkPasswordSuccess) {
|
// 更新用户ip对应的密码错误记录
|
if (!currentIPLimit) {
|
currentIPLimit = {
|
ip: clientIP,
|
error_times: 1,
|
last_error_time: Date.now()
|
}
|
loginIPLimit.push(currentIPLimit)
|
} else {
|
currentIPLimit.error_times++
|
currentIPLimit.last_error_time = Date.now()
|
}
|
await userCollection.doc(userRecord._id).update({
|
login_ip_limit: loginIPLimit
|
})
|
throw {
|
errCode: ERROR.PASSWORD_ERROR
|
}
|
}
|
const extraData = {}
|
if (refreshPasswordInfo) {
|
extraData.password = refreshPasswordInfo.passwordHash
|
extraData.password_secret_version = refreshPasswordInfo.version
|
}
|
|
const currentIPLimitIndex = loginIPLimit.indexOf(currentIPLimit)
|
if (currentIPLimitIndex > -1) {
|
loginIPLimit.splice(currentIPLimitIndex, 1)
|
}
|
extraData.login_ip_limit = loginIPLimit
|
return {
|
user: userRecord,
|
extraData
|
}
|
} catch (error) {
|
await this.middleware.uniIdLog({
|
success: false,
|
data: user,
|
type: LOG_TYPE.LOGIN
|
})
|
throw error
|
}
|
}
|
|
function checkLoginUserRecord (user) {
|
switch (user.status) {
|
case undefined:
|
case 0:
|
break
|
case 1:
|
throw {
|
errCode: ERROR.ACCOUNT_BANNED
|
}
|
case 2:
|
throw {
|
errCode: ERROR.ACCOUNT_AUDITING
|
}
|
case 3:
|
throw {
|
errCode: ERROR.ACCOUNT_AUDIT_FAILED
|
}
|
case 4:
|
throw {
|
errCode: ERROR.ACCOUNT_CLOSED
|
}
|
default:
|
break
|
}
|
}
|
|
async function thirdPartyLogin (params = {}) {
|
const {
|
user
|
} = params
|
return {
|
mobileComfirmd: user.mobile_comfirmd,
|
emailComfirmd: user.email_comfirmd
|
}
|
}
|
|
async function postLogin (params = {}) {
|
const {
|
user,
|
extraData,
|
isThirdParty = false
|
} = params
|
const {
|
clientIP
|
} = this.getUniversalClientInfo()
|
const uniIdToken = this.getUniversalUniIdToken()
|
const uid = user._id
|
const updateData = {
|
last_login_date: Date.now(),
|
last_login_ip: clientIP,
|
...extraData
|
}
|
const {
|
token,
|
tokenExpired
|
} = await this.uniIdCommon.createToken({
|
uid
|
})
|
|
if (uniIdToken) {
|
try {
|
await logout.call(this)
|
} catch (error) {}
|
}
|
|
await userCollection.doc(uid).update(updateData)
|
await this.middleware.uniIdLog({
|
data: {
|
user_id: uid
|
},
|
type: LOG_TYPE.LOGIN
|
})
|
return {
|
errCode: 0,
|
newToken: {
|
token,
|
tokenExpired
|
},
|
uid,
|
...(
|
isThirdParty
|
? thirdPartyLogin({
|
user
|
})
|
: {}
|
),
|
passwordConfirmed: !!user.password
|
}
|
}
|
|
module.exports = {
|
preLogin,
|
postLogin,
|
checkLoginUserRecord,
|
preLoginWithPassword
|
}
|