Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
hello_uni-id-pages
提交
2155ee49
H
hello_uni-id-pages
项目概览
DCloud
/
hello_uni-id-pages
通知
1054
Star
31
Fork
43
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
4
列表
看板
标记
里程碑
合并请求
2
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hello_uni-id-pages
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
4
Issue
4
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
2155ee49
编写于
10月 31, 2022
作者:
C
chenruilong
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 支持用户自定义密码加密校验规则
上级
39620190
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
252 addition
and
135 deletion
+252
-135
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js
...ages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js
+3
-3
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js
...s/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js
+202
-108
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js
...s/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js
+13
-8
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js
...dfunctions/uni-id-co/module/account/reset-pwd-by-email.js
+7
-3
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js
...oudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js
+7
-3
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js
...oud/cloudfunctions/uni-id-co/module/account/update-pwd.js
+6
-5
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js
...niCloud/cloudfunctions/uni-id-co/module/admin/add-user.js
+7
-2
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js
...loud/cloudfunctions/uni-id-co/module/admin/update-user.js
+7
-3
未找到文件。
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js
浏览文件 @
2155ee49
...
...
@@ -78,9 +78,9 @@ async function preLoginWithPassword (params = {}) {
}
}
const
passwordUtils
=
new
PasswordUtils
({
passwordHash
:
userRecord
.
passw
ord
,
passwordSecret
:
this
.
config
.
passwordSecret
,
passwordSecret
Version
:
userRecord
.
password_secret_version
userRec
ord
,
clientInfo
:
this
.
getClientInfo
()
,
passwordSecret
:
this
.
config
.
passwordSecret
})
const
{
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js
浏览文件 @
2155ee49
...
...
@@ -2,72 +2,161 @@ const {
getType
}
=
require
(
'
../../common/utils
'
)
const
crypto
=
require
(
'
crypto
'
)
const
createConfig
=
require
(
'
uni-config-center
'
)
const
shareConfig
=
createConfig
({
pluginId
:
'
uni-id
'
})
let
customPassword
=
{}
if
(
shareConfig
.
hasFile
(
'
custom-password.js
'
))
{
customPassword
=
shareConfig
.
requireFile
(
'
custom-password.js
'
)
||
{}
}
const
PasswordMethodMaps
=
{
A
:
'
hmac-sha1
'
,
B
:
'
hmac-sha256
'
const
passwordAlgorithmMap
=
{
UNI_ID_HMAC_SHA1
:
'
hmac-sha1
'
,
UNI_ID_HMAC_SHA256
:
'
hmac-sha256
'
,
UNI_ID_CUSTOM
:
'
custom
'
}
const
PasswordMethodFlagMaps
=
Object
.
keys
(
PasswordMethodMaps
).
reduce
((
res
,
item
)
=>
{
res
[
PasswordMethodMaps
[
item
]]
=
item
const
passwordAlgorithmKeyMap
=
Object
.
keys
(
passwordAlgorithmMap
).
reduce
((
res
,
item
)
=>
{
res
[
passwordAlgorithmMap
[
item
]]
=
item
return
res
},
{})
const
PasswordHashMethod
=
{
'
hmac-sha1
'
:
function
(
content
,
secret
)
{
const
passwordExtMethod
=
{
[
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA1
]:
{
verify
({
password
})
{
const
{
password_secret_version
:
passwordSecretVersion
}
=
this
.
userRecord
const
passwordSecret
=
this
.
_getSecretByVersion
({
version
:
passwordSecretVersion
})
const
{
passwordHash
}
=
this
.
encrypt
({
password
,
passwordSecret
})
return
passwordHash
===
this
.
userRecord
.
password
},
encrypt
({
password
,
passwordSecret
})
{
const
{
value
:
secret
,
version
}
=
passwordSecret
const
hmac
=
crypto
.
createHmac
(
'
sha1
'
,
secret
.
toString
(
'
ascii
'
))
hmac
.
update
(
content
)
return
hmac
.
digest
(
'
hex
'
)
hmac
.
update
(
password
)
return
{
passwordHash
:
hmac
.
digest
(
'
hex
'
),
version
}
}
},
[
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA256
]:
{
verify
({
password
})
{
const
parse
=
this
.
_parsePassword
()
const
passwordHash
=
crypto
.
createHmac
(
parse
.
algorithm
,
parse
.
salt
).
update
(
password
).
digest
(
'
hex
'
)
return
passwordHash
===
parse
.
hash
},
encrypt
({
password
,
passwordSecret
})
{
const
{
version
}
=
passwordSecret
// 默认使用 sha256 加密算法
const
salt
=
crypto
.
randomBytes
(
10
).
toString
(
'
hex
'
)
const
sha256Hash
=
crypto
.
createHmac
(
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA256
.
substring
(
5
),
salt
).
update
(
password
).
digest
(
'
hex
'
)
const
algorithm
=
passwordAlgorithmKeyMap
[
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA256
]
// B 为固定值,对应 PasswordMethodMaps 中的 sha256算法
// hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash]
const
passwordHash
=
`$
${
algorithm
}
$
${
salt
.
length
}
$
${
salt
}${
sha256Hash
}
`
return
{
passwordHash
,
version
}
}
},
[
passwordAlgorithmMap
.
UNI_ID_CUSTOM
]:
{
verify
({
password
,
passwordSecret
})
{
console
.
log
(
customPassword
)
if
(
!
customPassword
.
verifyPassword
)
throw
new
Error
(
'
verifyPassword method not found in custom password file
'
)
// return true or false
return
customPassword
.
verifyPassword
({
password
,
passwordSecret
,
userRecord
:
this
.
userRecord
,
clientInfo
:
this
.
clientInfo
})
},
'
hmac-sha256
'
:
function
(
content
,
secret
)
{
const
hmac
=
crypto
.
createHmac
(
'
sha256
'
,
secret
)
hmac
.
update
(
content
)
return
hmac
.
digest
(
'
hex
'
)
encrypt
({
password
,
passwordSecret
})
{
if
(
!
customPassword
.
encryptPassword
)
throw
new
Error
(
'
encryptPassword method not found in custom password file
'
)
// return object<{passwordHash: string, version: number}>
return
customPassword
.
encryptPassword
({
password
,
passwordSecret
,
clientInfo
:
this
.
clientInfo
})
}
}
}
class
PasswordUtils
{
constructor
({
passwordHash
=
''
,
passwordSecret
=
''
,
passwordSecret
Version
userRecord
=
{}
,
clientInfo
,
passwordSecret
}
=
{})
{
this
.
passwordHash
=
passwordHash
this
.
passwordSecretVersion
=
passwordSecretVersion
if
(
!
clientInfo
)
throw
new
Error
(
'
Invalid clientInfo
'
)
if
(
!
passwordSecret
)
throw
new
Error
(
'
Invalid password secret
'
)
this
.
password
=
this
.
parsePassword
()
this
.
clientInfo
=
clientInfo
this
.
userRecord
=
userRecord
this
.
passwordSecret
=
this
.
prePasswordSecret
(
passwordSecret
)
}
// 老版本会存在 passwordSecret
if
(
passwordSecret
)
{
const
passwordSecretType
=
getType
(
passwordSecret
)
if
(
passwordSecretType
===
'
array
'
)
{
this
.
passwordSecret
=
passwordSecret
.
sort
((
a
,
b
)
=>
{
return
a
.
version
-
b
.
version
/**
* passwordSecret 预处理
* @param passwordSecret
* @return {*[]}
*/
prePasswordSecret
(
passwordSecret
)
{
const
newPasswordSecret
=
[]
if
(
getType
(
passwordSecret
)
===
'
string
'
)
{
newPasswordSecret
.
push
({
value
:
passwordSecret
,
type
:
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA1
})
}
else
if
(
getType
(
passwordSecret
)
===
'
array
'
)
{
for
(
const
secret
of
passwordSecret
.
sort
((
a
,
b
)
=>
a
.
version
-
b
.
version
))
{
newPasswordSecret
.
push
({
...
secret
,
// 没有 type 设置默认 type hmac-sha1
type
:
secret
.
type
||
passwordAlgorithmMap
.
UNI_ID_HMAC_SHA1
})
}
else
if
(
passwordSecretType
===
'
string
'
)
{
this
.
passwordSecret
=
[{
value
:
passwordSecret
}]
}
}
}
else
{
throw
new
Error
(
'
Invalid password secret
'
)
}
parsePassword
()
{
const
[
algorithmKey
=
''
,
cost
=
0
,
hashStr
=
''
]
=
this
.
passwordHash
.
split
(
'
$
'
).
filter
(
key
=>
key
)
const
algorithm
=
PasswordMethodMaps
[
algorithmKey
]
||
null
const
salt
=
hashStr
.
substring
(
0
,
Number
(
cost
))
const
hash
=
hashStr
.
substring
(
Number
(
cost
))
return
newPasswordSecret
}
return
{
algorithm
,
salt
,
hash
/**
* 获取最新加密密钥
* @return {*}
* @private
*/
_getLastestSecret
()
{
return
this
.
passwordSecret
[
this
.
passwordSecret
.
length
-
1
]
}
_getOldestSecret
()
{
return
this
.
passwordSecret
[
0
]
}
getSecretByVersion
(
params
=
{})
{
const
{
version
}
=
params
_getSecretByVersion
({
version
}
=
{})
{
if
(
!
version
&&
version
!==
0
)
{
return
this
.
getOldestSecret
()
return
this
.
_
getOldestSecret
()
}
if
(
this
.
passwordSecret
.
length
===
1
)
{
return
this
.
passwordSecret
[
0
]
...
...
@@ -75,92 +164,97 @@ class PasswordUtils {
return
this
.
passwordSecret
.
find
(
item
=>
item
.
version
===
version
)
}
getLastestSecret
()
{
return
this
.
passwordSecret
[
this
.
passwordSecret
.
length
-
1
]
}
getOldestSecret
()
{
return
this
.
passwordSecret
[
0
]
/**
* 获取密码的验证/加密方法
* @param passwordSecret
* @return {*[]}
* @private
*/
_getPasswordExt
(
passwordSecret
)
{
const
ext
=
passwordExtMethod
[
passwordSecret
.
type
]
if
(
!
ext
)
{
throw
new
Error
(
`暂不支持
${
passwordSecret
.
type
}
类型的加密算法`
)
}
checkUserPassword
(
params
=
{})
{
const
{
password
,
autoRefresh
=
true
}
=
params
let
passwordHash
const
passwordExt
=
Object
.
create
(
null
)
if
(
this
.
password
.
algorithm
)
{
passwordHash
=
PasswordHashMethod
[
this
.
password
.
algorithm
](
password
,
this
.
password
.
salt
)
}
else
{
const
hash
=
this
.
generatePasswordHash
({
password
})
for
(
const
key
in
ext
)
{
passwordExt
[
key
]
=
ext
[
key
].
bind
(
Object
.
assign
(
this
,
Object
.
keys
(
ext
).
reduce
((
res
,
item
)
=>
{
if
(
item
!==
key
)
{
res
[
item
]
=
ext
[
item
].
bind
(
this
)
}
return
res
},
{})))
}
passwordHash
=
hash
.
passwordHash
return
passwordExt
}
if
(
passwordHash
!==
this
.
password
.
hash
&&
passwordHash
!==
this
.
passwordHash
)
{
_parsePassword
()
{
const
[
algorithmKey
=
''
,
cost
=
0
,
hashStr
=
''
]
=
this
.
userRecord
.
password
.
split
(
'
$
'
).
filter
(
key
=>
key
)
const
algorithm
=
passwordAlgorithmMap
[
algorithmKey
]
?
passwordAlgorithmMap
[
algorithmKey
].
substring
(
5
)
:
null
const
salt
=
hashStr
.
substring
(
0
,
Number
(
cost
))
const
hash
=
hashStr
.
substring
(
Number
(
cost
))
return
{
success
:
false
algorithm
,
salt
,
hash
}
}
let
refreshPasswordInfo
if
(
autoRefresh
)
{
refreshPasswordInfo
=
this
.
generatePasswordHash
({
/**
* 生成加密后的密码
* @param {String} password 密码
*/
generatePasswordHash
({
password
})
{
if
(
!
password
)
throw
new
Error
(
'
Invalid password
'
)
const
passwordSecret
=
this
.
_getLastestSecret
()
const
ext
=
this
.
_getPasswordExt
(
passwordSecret
)
const
{
passwordHash
,
version
}
=
ext
.
encrypt
({
password
,
forceUseInternal
:
true
passwordSecret
})
}
return
{
success
:
true
,
refreshPasswordInfo
passwordHash
,
version
}
}
generatePasswordHash
(
params
=
{})
{
let
{
password
,
forceUseInternal
=
false
}
=
params
if
(
getType
(
password
)
!==
'
string
'
)
{
throw
new
Error
(
'
Invalid password
'
)
}
password
=
password
&&
password
.
trim
()
if
(
!
password
)
{
throw
new
Error
(
'
Invalid password
'
)
}
/**
* 密码校验
* @param {String} password
* @param {Boolean} autoRefresh
* @return {{refreshPasswordInfo: {version: *, passwordHash: *}, success: boolean}|{success: boolean}}
*/
checkUserPassword
({
password
,
autoRefresh
=
true
})
{
if
(
!
password
)
throw
new
Error
(
'
Invalid password
'
)
// 没有 passwordSecret,使用内置算法(新版)
if
(
forceUseInternal
||
!
this
.
passwordSecret
)
{
// 默认使用 sha256 加密算法
const
salt
=
crypto
.
randomBytes
(
10
).
toString
(
'
hex
'
)
const
sha256Hash
=
PasswordHashMethod
[
'
hmac-sha256
'
](
password
,
salt
)
const
algorithm
=
PasswordMethodFlagMaps
[
'
hmac-sha256
'
]
// B 为固定值,对应 PasswordMethodMaps 中的 sha256算法
// hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash]
const
hashStr
=
`$
${
algorithm
}
$
${
salt
.
length
}
$
${
salt
}${
sha256Hash
}
`
const
{
password_secret_version
:
passwordSecretVersion
}
=
this
.
userRecord
const
passwordSecret
=
this
.
_getSecretByVersion
({
version
:
passwordSecretVersion
})
const
ext
=
this
.
_getPasswordExt
(
passwordSecret
)
const
success
=
ext
.
verify
({
password
,
passwordSecret
})
if
(
!
success
)
{
return
{
passwordHash
:
hashStr
success
:
false
}
}
// 旧版本兼容
let
secret
if
(
this
.
passwordSecretVersion
)
{
secret
=
this
.
getSecretByVersion
({
version
:
this
.
passwordSecretVersion
})
}
else
{
secret
=
this
.
getLastestSecret
()
let
refreshPasswordInfo
if
(
autoRefresh
&&
passwordSecretVersion
!==
this
.
_getLastestSecret
().
version
)
{
refreshPasswordInfo
=
this
.
generatePasswordHash
({
password
})
}
return
{
passwordHash
:
PasswordHashMethod
[
'
hmac-sha1
'
](
password
,
secret
.
value
)
,
version
:
secret
.
version
success
:
true
,
refreshPasswordInfo
}
}
}
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js
浏览文件 @
2155ee49
...
...
@@ -18,7 +18,7 @@ const {
const
PasswordUtils
=
require
(
'
./password
'
)
const
merge
=
require
(
'
lodash.merge
'
)
async
function
realPreRegister
(
params
=
{})
{
async
function
realPreRegister
(
params
=
{})
{
const
{
user
}
=
params
...
...
@@ -33,7 +33,7 @@ async function realPreRegister(params = {}) {
}
}
async
function
preRegister
(
params
=
{})
{
async
function
preRegister
(
params
=
{})
{
try
{
await
realPreRegister
.
call
(
this
,
params
)
}
catch
(
error
)
{
...
...
@@ -45,7 +45,7 @@ async function preRegister(params = {}) {
}
}
async
function
preRegisterWithPassword
(
params
=
{})
{
async
function
preRegisterWithPassword
(
params
=
{})
{
const
{
user
,
password
...
...
@@ -53,14 +53,19 @@ async function preRegisterWithPassword(params = {}) {
await
preRegister
.
call
(
this
,
{
user
})
const
passwordUtils
=
new
PasswordUtils
()
const
passwordUtils
=
new
PasswordUtils
({
clientInfo
:
this
.
getClientInfo
(),
passwordSecret
:
this
.
config
.
passwordSecret
})
const
{
passwordHash
passwordHash
,
version
}
=
passwordUtils
.
generatePasswordHash
({
password
})
const
extraData
=
{
password
:
passwordHash
password
:
passwordHash
,
password_secret_version
:
version
}
return
{
user
,
...
...
@@ -68,7 +73,7 @@ async function preRegisterWithPassword(params = {}) {
}
}
async
function
thirdPartyRegister
({
async
function
thirdPartyRegister
({
user
=
{}
}
=
{})
{
return
{
...
...
@@ -77,7 +82,7 @@ async function thirdPartyRegister({
}
}
async
function
postRegister
(
params
=
{})
{
async
function
postRegister
(
params
=
{})
{
const
{
user
,
extraData
=
{},
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js
浏览文件 @
2155ee49
...
...
@@ -92,14 +92,18 @@ module.exports = async function (params = {}) {
}
const
{
_id
:
uid
}
=
userMatched
[
0
]
const
{
passwordHash
}
=
new
PasswordUtils
().
generatePasswordHash
({
passwordHash
,
version
}
=
new
PasswordUtils
({
clientInfo
:
this
.
getClientInfo
(),
passwordSecret
:
this
.
config
.
passwordSecret
}).
generatePasswordHash
({
password
})
// 更新用户密码
await
userCollection
.
doc
(
uid
).
update
({
password
:
passwordHash
,
password_secret_version
:
dbCmd
.
remove
()
,
password_secret_version
:
version
,
valid_token_date
:
Date
.
now
()
})
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js
浏览文件 @
2155ee49
...
...
@@ -92,14 +92,18 @@ module.exports = async function (params = {}) {
}
const
{
_id
:
uid
}
=
userMatched
[
0
]
const
{
passwordHash
}
=
new
PasswordUtils
().
generatePasswordHash
({
passwordHash
,
version
}
=
new
PasswordUtils
({
clientInfo
:
this
.
getClientInfo
(),
passwordSecret
:
this
.
config
.
passwordSecret
}).
generatePasswordHash
({
password
})
// 更新用户密码
await
userCollection
.
doc
(
uid
).
update
({
password
:
passwordHash
,
password_secret_version
:
dbCmd
.
remove
()
,
password_secret_version
:
version
,
valid_token_date
:
Date
.
now
()
})
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js
浏览文件 @
2155ee49
...
...
@@ -32,9 +32,9 @@ module.exports = async function (params = {}) {
newPassword
}
=
params
const
passwordUtils
=
new
PasswordUtils
({
passwordHash
:
userRecord
.
passw
ord
,
passwordSecret
:
this
.
config
.
passwordSecret
,
passwordSecret
Version
:
userRecord
.
password_secret_version
userRec
ord
,
clientInfo
:
this
.
getClientInfo
()
,
passwordSecret
:
this
.
config
.
passwordSecret
})
const
{
...
...
@@ -51,14 +51,15 @@ module.exports = async function (params = {}) {
}
const
{
passwordHash
passwordHash
,
version
}
=
passwordUtils
.
generatePasswordHash
({
password
:
newPassword
})
await
userCollection
.
doc
(
uid
).
update
({
password
:
passwordHash
,
password_secret_version
:
dbCmd
.
remove
()
,
password_secret_version
:
version
,
valid_token_date
:
Date
.
now
()
// refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码
})
// 执行更新密码操作后客户端应将用户退出重新登录
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js
浏览文件 @
2155ee49
...
...
@@ -82,15 +82,20 @@ module.exports = async function (params = {}) {
errCode
:
ERROR
.
ACCOUNT_EXISTS
}
}
const
passwordUtils
=
new
PasswordUtils
()
const
passwordUtils
=
new
PasswordUtils
({
clientInfo
:
this
.
getClientInfo
(),
passwordSecret
:
this
.
config
.
passwordSecret
})
const
{
passwordHash
passwordHash
,
version
}
=
passwordUtils
.
generatePasswordHash
({
password
})
const
data
=
{
username
,
password
:
passwordHash
,
password_secret_version
:
version
,
dcloud_appid
:
authorizedApp
||
[],
nickname
,
role
:
role
||
[],
...
...
uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js
浏览文件 @
2155ee49
...
...
@@ -106,15 +106,19 @@ module.exports = async function (params = {}) {
}
if
(
password
)
{
const
passwordUtils
=
new
PasswordUtils
()
const
passwordUtils
=
new
PasswordUtils
({
clientInfo
:
this
.
getClientInfo
(),
passwordSecret
:
this
.
config
.
passwordSecret
})
const
{
passwordHash
passwordHash
,
version
}
=
passwordUtils
.
generatePasswordHash
({
password
})
data
.
password
=
passwordHash
data
.
password_secret_version
=
dbCmd
.
remove
()
data
.
password_secret_version
=
version
}
await
userCollection
.
doc
(
uid
).
update
(
data
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录