Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nouiWithSpringMVC
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gechengyang
nouiWithSpringMVC
Commits
98654e0b
Commit
98654e0b
authored
Oct 07, 2020
by
WeiCong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完善数据安全框架
parent
a20df4c4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
361 additions
and
269 deletions
+361
-269
NoUiRequest.java
...va/org/sss/presentation/noui/api/request/NoUiRequest.java
+19
-0
AbstractCommonController.java
...resentation/noui/controller/AbstractCommonController.java
+198
-200
DataSecurityUtil.java
...java/org/sss/presentation/noui/util/DataSecurityUtil.java
+136
-67
security.properties
src/main/resources/security.properties
+8
-2
No files found.
src/main/java/org/sss/presentation/noui/api/request/NoUiRequest.java
View file @
98654e0b
...
...
@@ -19,6 +19,8 @@ public class NoUiRequest {
private
Map
<
String
,
?>
dataMap
=
new
HashMap
<
String
,
Object
>();
private
Map
<
String
,
?>
saveDisplayMap
=
new
HashMap
<
String
,
Object
>();
private
boolean
isSecurity
=
false
;
private
String
reqUrl
;
private
String
trnName
;
public
NoUiRequest
()
{
...
...
@@ -34,6 +36,15 @@ public class NoUiRequest {
this
.
userId
=
userId
;
this
.
terminalType
=
terminalType
;
this
.
mappingUrl
=
mappingUrl
;
String
[]
mappingArgs
=
mappingUrl
.
split
(
"/"
);
if
(
mappingArgs
.
length
>
1
){
this
.
trnName
=
mappingArgs
[
mappingArgs
.
length
-
2
];
if
(
request
.
getRequestURI
().
indexOf
(
this
.
trnName
)>
0
){
this
.
reqUrl
=
request
.
getRequestURI
().
substring
(
request
.
getRequestURI
().
indexOf
(
this
.
trnName
)-
1
);
}
else
{
this
.
reqUrl
=
mappingUrl
;
}
}
if
(!
StringUtil
.
isEmpty
(
security
)){
this
.
isSecurity
=
true
;
}
...
...
@@ -125,4 +136,12 @@ public class NoUiRequest {
public
boolean
isSecurity
()
{
return
isSecurity
;
}
public
String
getReqUrl
()
{
return
reqUrl
;
}
public
String
getTrnName
()
{
return
trnName
;
}
}
src/main/java/org/sss/presentation/noui/controller/AbstractCommonController.java
View file @
98654e0b
...
...
@@ -32,218 +32,216 @@ import java.util.HashMap;
import
java.util.List
;
import
java.util.Map
;
public
abstract
class
AbstractCommonController
{
protected
static
final
Log
log
=
LogFactory
.
getLog
(
AbstractCommonController
.
class
);
protected
static
String
ON_CLICK
=
"ON_CLICK"
;
protected
static
String
INIT
=
"INIT"
;
protected
static
String
ON_CHANGE
=
"ON_CHANGE"
;
protected
static
String
ON_CHECK
=
"ON_CHECK"
;
protected
static
String
ON_STREAM_UPLOAD
=
"ON_STREAM_UPLOAD"
;
protected
static
String
ON_STREAM_DOWNLOAD
=
"ON_STREAM_DOWNLOAD"
;
@Autowired
private
NoUiVersion
noUiVersion
;
public
String
getMainPanel
()
{
return
""
;
}
@SuppressWarnings
(
"unchecked"
)
public
Object
event
(
String
mappingUrl
,
String
eventType
,
Map
<
String
,
Object
>
dataMap
,
MultipartFile
file
,
HttpServletRequest
request
,
HttpServletResponse
response
)
{
NoUiContext
context
=
null
;
Result
ret
=
null
;
public
abstract
class
AbstractCommonController
{
protected
static
final
Log
log
=
LogFactory
.
getLog
(
AbstractCommonController
.
class
);
protected
static
String
ON_CLICK
=
"ON_CLICK"
;
protected
static
String
INIT
=
"INIT"
;
protected
static
String
ON_CHANGE
=
"ON_CHANGE"
;
protected
static
String
ON_CHECK
=
"ON_CHECK"
;
protected
static
String
ON_STREAM_UPLOAD
=
"ON_STREAM_UPLOAD"
;
protected
static
String
ON_STREAM_DOWNLOAD
=
"ON_STREAM_DOWNLOAD"
;
@Autowired
private
NoUiVersion
noUiVersion
;
public
String
getMainPanel
()
{
return
""
;
}
@SuppressWarnings
(
"unchecked"
)
public
Object
event
(
String
mappingUrl
,
String
eventType
,
Map
<
String
,
Object
>
dataMap
,
MultipartFile
file
,
HttpServletRequest
request
,
HttpServletResponse
response
)
{
NoUiContext
context
=
null
;
Result
ret
=
null
;
String
serverEnc
=
null
;
try
{
NoUiRequest
noUiRequest
=
new
NoUiRequest
(
request
,
mappingUrl
,
dataMap
);
Alias
alias
=
new
Alias
(
mappingUrl
);
String
trnName
=
alias
.
getTrnName
();
Map
<
String
,
?>
paramsMap
=
noUiRequest
.
getParamsMap
();
context
=
NoUiContextManager
.
createNoUiContext
(
noUiRequest
);
// 交易参数赋值
for
(
String
key
:
paramsMap
.
keySet
())
{
context
.
getSession
().
storeData
(
key
,
paramsMap
.
get
(
key
));
}
// 设置old sysmod
RedisLoginInfo
redisLoginInfo
=
null
;
if
(
!
StringUtils
.
isEmpty
(
noUiRequest
.
getUserId
())
)
//开放模式下
redisLoginInfo
=
(
RedisLoginInfo
)
RedisUtil
.
get
(
StringUtil
.
userUniqueId
(
noUiRequest
));
if
(
redisLoginInfo
!=
null
)
{
NoUiPresentationUtil
.
setSysmod
(
context
,
(
byte
[])
redisLoginInfo
.
getSysmod
());
context
.
setRedisLoginInfo
(
redisLoginInfo
);
}
// 交易跳转
context
.
getSession
().
chain
(
true
,
trnName
);
//执行可能存在的主面板的初始化
if
(
this
.
getMainPanel
().
length
()
>
0
)
{
IPanel
mainPanel
=
(
IPanel
)
context
.
getSession
().
getBaseObject
(
null
,
this
.
getMainPanel
());
mainPanel
.
invokeDefaultRules
(
context
);
}
// 模型赋值
NoUiPresentationUtil
.
hanleInput
(
context
,
noUiRequest
,
alias
);
try
{
NoUiRequest
noUiRequest
=
new
NoUiRequest
(
request
,
mappingUrl
,
dataMap
);
Alias
alias
=
new
Alias
(
mappingUrl
);
String
trnName
=
alias
.
getTrnName
();
Map
<
String
,
?>
paramsMap
=
noUiRequest
.
getParamsMap
();
context
=
NoUiContextManager
.
createNoUiContext
(
noUiRequest
);
// 交易参数赋值
for
(
String
key
:
paramsMap
.
keySet
())
{
context
.
getSession
().
storeData
(
key
,
paramsMap
.
get
(
key
));
}
// 设置old sysmod
RedisLoginInfo
redisLoginInfo
=
null
;
if
(!
StringUtils
.
isEmpty
(
noUiRequest
.
getUserId
()))
//开放模式下
redisLoginInfo
=
(
RedisLoginInfo
)
RedisUtil
.
get
(
StringUtil
.
userUniqueId
(
noUiRequest
));
if
(
redisLoginInfo
!=
null
)
{
NoUiPresentationUtil
.
setSysmod
(
context
,
(
byte
[])
redisLoginInfo
.
getSysmod
());
context
.
setRedisLoginInfo
(
redisLoginInfo
);
}
// 交易跳转
context
.
getSession
().
chain
(
true
,
trnName
);
//执行可能存在的主面板的初始化
if
(
this
.
getMainPanel
().
length
()
>
0
)
{
IPanel
mainPanel
=
(
IPanel
)
context
.
getSession
().
getBaseObject
(
null
,
this
.
getMainPanel
());
mainPanel
.
invokeDefaultRules
(
context
);
}
// 模型赋值
NoUiPresentationUtil
.
hanleInput
(
context
,
noUiRequest
,
alias
);
//数据安全性拦截-篡改数据拦截
if
(
DataSecurityUtil
.
isSafeMode
()
&&
noUiRequest
.
isSecurity
()){
if
(
paramsMap
.
containsKey
(
DataSecurityUtil
.
BACKGROUND_ID
)){
String
[]
clientpars
=
DataSecurityUtil
.
getSafeConfigByTrnName
(
context
,
trnName
);
if
(!
ArrayUtils
.
isEmpty
(
clientpars
)){
//合法性校验操作(场景:用户做修改、删除时调用)
serverEnc
=
(
String
)
paramsMap
.
get
(
DataSecurityUtil
.
BACKGROUND_ID
);
String
errmsg
=
null
;
if
((
errmsg
=
DataSecurityUtil
.
checkIllegalData
(
serverEnc
,
clientpars
,
noUiRequest
.
getUserId
()))!=
null
){
Result
rt
=
new
Result
(
ErrorCodes
.
ERROR
,
errmsg
,
null
,
noUiVersion
.
getVersion
());
return
rt
;
if
(
DataSecurityUtil
.
isSafeMode
()
&&
noUiRequest
.
isSecurity
())
{
if
(
DataSecurityUtil
.
needDecrypt
(
noUiRequest
.
getReqUrl
()))
{
if
(
paramsMap
.
containsKey
(
DataSecurityUtil
.
BACKGROUND_ID
))
{
String
[]
clientpars
=
DataSecurityUtil
.
getSafeConfigByReqUrl
(
context
,
noUiRequest
.
getReqUrl
()
+
DataSecurityUtil
.
DECRYPT_FIX
);
if
(!
ArrayUtils
.
isEmpty
(
clientpars
))
{
//合法性校验操作(场景:用户做修改、删除时调用)
serverEnc
=
(
String
)
paramsMap
.
get
(
DataSecurityUtil
.
BACKGROUND_ID
);
String
errmsg
=
null
;
if
((
errmsg
=
DataSecurityUtil
.
checkIllegalData
(
serverEnc
,
clientpars
,
noUiRequest
.
getUserId
()))
!=
null
)
{
Result
rt
=
new
Result
(
ErrorCodes
.
ERROR
,
errmsg
,
null
,
noUiVersion
.
getVersion
());
return
rt
;
}
}
}
else
{
Result
rt
=
new
Result
(
ErrorCodes
.
ERROR
,
DataSecurityUtil
.
ERROR_SERVERENC_NULL
,
null
,
noUiVersion
.
getVersion
());
return
rt
;
}
}
}
if
(
eventType
.
equals
(
ON_CLICK
))
{
IBaseObject
dataField
=
baseObject
(
context
,
noUiRequest
,
alias
);
((
IDatafield
<?>)
dataField
).
invokeEventRules
(
context
,
EventType
.
ON_CLICK
,
null
);
}
else
if
(
eventType
.
equals
(
ON_CHANGE
))
{
IBaseObject
dataField
=
baseObject
(
context
,
noUiRequest
,
alias
);
((
IDatafield
<?>)
dataField
).
invokeEventRules
(
context
,
EventType
.
ON_CHANGE
,
null
);
}
else
if
(
eventType
.
equals
(
ON_CHECK
))
{
for
(
String
aliasKey
:
noUiRequest
.
getDataMap
().
keySet
())
{
if
(
aliasKey
.
startsWith
(
Constants
.
MAPPING_PRE
))
{
continue
;
}
String
realPath
=
alias
.
getRelPath
(
aliasKey
);
IBaseObject
currentDataField
=
(
IDatafield
<?>)
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
realPath
);
if
(
currentDataField
instanceof
IDatafield
<?>)
{
((
IDatafield
<?>)
currentDataField
).
invokeCheckRules
(
context
);
}
}
}
else
if
(
eventType
.
equals
(
ON_STREAM_UPLOAD
)
&&
file
!=
null
)
{
@SuppressWarnings
(
"rawtypes"
)
IDatafield
dataField
=
(
IDatafield
)
baseObject
(
context
,
noUiRequest
,
alias
);
IStream
stream
=
(
IStream
)
dataField
.
getValue
();
stream
.
setName
(
file
.
getOriginalFilename
());
stream
.
setType
(
file
.
getContentType
());
log
.
info
(
"文件表单 key:"
+
file
.
getOriginalFilename
()
+
",size:"
+
file
.
getSize
());
IOUtils
.
copy
(
file
.
getInputStream
(),
stream
.
getOutputStream
(),
1024
);
dataField
.
invokeEventRules
(
context
,
EventType
.
ON_STREAM_UPLOAD
,
null
);
}
else
if
(
eventType
.
equals
(
ON_STREAM_DOWNLOAD
))
{
@SuppressWarnings
(
"rawtypes"
)
IDatafield
dataField
=
(
IDatafield
)
baseObject
(
context
,
noUiRequest
,
alias
);
IStream
stream
=
(
IStream
)
dataField
.
getValue
();
byte
[]
data
=
IOUtils
.
readFully
(
stream
.
getInputStream
(),
(
int
)
stream
.
size
());
dataField
.
invokeEventRules
(
context
,
EventType
.
ON_STREAM_DOWNLOAD
,
null
);
IOUtils
.
write
(
data
,
response
.
getOutputStream
());
}
// 保存新的RedisLoginInfo
if
(
redisLoginInfo
!=
null
)
//当为开放模式下,redisLoginInfo 为空
{
byte
[]
sysmodBytes
=
NoUiPresentationUtil
.
sysmodToBytes
(
context
);
redisLoginInfo
.
setSysmod
(
sysmodBytes
);
RedisUtil
.
set
(
StringUtil
.
userUniqueId
(
noUiRequest
),
redisLoginInfo
);
}
Map
<
String
,
Object
>
afterReturnData
=
handleReturnData
(
eventType
,
context
,
noUiRequest
,
alias
);
if
(
eventType
.
equals
(
ON_CLICK
))
{
IBaseObject
dataField
=
baseObject
(
context
,
noUiRequest
,
alias
);
((
IDatafield
<?>)
dataField
).
invokeEventRules
(
context
,
EventType
.
ON_CLICK
,
null
);
}
else
if
(
eventType
.
equals
(
ON_CHANGE
))
{
IBaseObject
dataField
=
baseObject
(
context
,
noUiRequest
,
alias
);
((
IDatafield
<?>)
dataField
).
invokeEventRules
(
context
,
EventType
.
ON_CHANGE
,
null
);
}
else
if
(
eventType
.
equals
(
ON_CHECK
))
{
for
(
String
aliasKey
:
noUiRequest
.
getDataMap
().
keySet
())
{
if
(
aliasKey
.
startsWith
(
Constants
.
MAPPING_PRE
))
{
continue
;
}
String
realPath
=
alias
.
getRelPath
(
aliasKey
);
IBaseObject
currentDataField
=
(
IDatafield
<?>)
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
realPath
);
if
(
currentDataField
instanceof
IDatafield
<?>)
{
((
IDatafield
<?>)
currentDataField
).
invokeCheckRules
(
context
);
}
}
}
else
if
(
eventType
.
equals
(
ON_STREAM_UPLOAD
)
&&
file
!=
null
)
{
@SuppressWarnings
(
"rawtypes"
)
IDatafield
dataField
=
(
IDatafield
)
baseObject
(
context
,
noUiRequest
,
alias
);
IStream
stream
=
(
IStream
)
dataField
.
getValue
();
stream
.
setName
(
file
.
getOriginalFilename
());
stream
.
setType
(
file
.
getContentType
());
log
.
info
(
"文件表单 key:"
+
file
.
getOriginalFilename
()
+
",size:"
+
file
.
getSize
());
IOUtils
.
copy
(
file
.
getInputStream
(),
stream
.
getOutputStream
(),
1024
);
dataField
.
invokeEventRules
(
context
,
EventType
.
ON_STREAM_UPLOAD
,
null
);
}
else
if
(
eventType
.
equals
(
ON_STREAM_DOWNLOAD
))
{
@SuppressWarnings
(
"rawtypes"
)
IDatafield
dataField
=
(
IDatafield
)
baseObject
(
context
,
noUiRequest
,
alias
);
IStream
stream
=
(
IStream
)
dataField
.
getValue
();
byte
[]
data
=
IOUtils
.
readFully
(
stream
.
getInputStream
(),
(
int
)
stream
.
size
());
dataField
.
invokeEventRules
(
context
,
EventType
.
ON_STREAM_DOWNLOAD
,
null
);
IOUtils
.
write
(
data
,
response
.
getOutputStream
());
}
// 保存新的RedisLoginInfo
if
(
redisLoginInfo
!=
null
)
//当为开放模式下,redisLoginInfo 为空
{
byte
[]
sysmodBytes
=
NoUiPresentationUtil
.
sysmodToBytes
(
context
);
redisLoginInfo
.
setSysmod
(
sysmodBytes
);
RedisUtil
.
set
(
StringUtil
.
userUniqueId
(
noUiRequest
),
redisLoginInfo
);
}
Map
<
String
,
Object
>
afterReturnData
=
handleReturnData
(
eventType
,
context
,
noUiRequest
,
alias
);
//数据安全性拦截-篡改数据加密
if
(
DataSecurityUtil
.
isSafeMode
()
&&
noUiRequest
.
isSecurity
())
{
if
(!
paramsMap
.
containsKey
(
DataSecurityUtil
.
BACKGROUND_ID
))
{
if
(
DataSecurityUtil
.
isSafeMode
()
&&
noUiRequest
.
isSecurity
())
{
if
(
DataSecurityUtil
.
needEncrypt
(
noUiRequest
.
getReqUrl
()))
{
//加密操作(场景:用户查询指定信息时调用,后续会做修改,删除等操作)
String
[]
pars
=
DataSecurityUtil
.
getSafeConfigByTrnName
(
context
,
trnName
);
if
(!
ArrayUtils
.
isEmpty
(
pars
)){
serverEnc
=
DataSecurityUtil
.
encrypt
(
pars
,
noUiRequest
.
getUserId
());
afterReturnData
.
put
(
DataSecurityUtil
.
BACKGROUND_ID
,
serverEnc
);
}
String
[]
pars
=
DataSecurityUtil
.
getSafeConfigByReqUrl
(
context
,
noUiRequest
.
getReqUrl
()
+
DataSecurityUtil
.
ENCRYPT_FIX
);
serverEnc
=
DataSecurityUtil
.
encrypt
(
pars
,
noUiRequest
.
getUserId
());
afterReturnData
.
put
(
DataSecurityUtil
.
BACKGROUND_ID
,
serverEnc
);
}
}
ret
=
ResultUtil
.
result
(
NoUiPresentationUtil
.
retCode
(
context
),
NoUiPresentationUtil
.
retMsg
(
context
),
afterReturnData
,
NoUiPresentationUtil
.
handleErrorReturnData
(
context
,
alias
),
NoUiPresentationUtil
.
handleCodeTableReturnData
(
context
,
alias
),
noUiVersion
.
getVersion
());
}
catch
(
Exception
e
)
{
log
.
error
(
"OnClick command error"
,
e
);
ret
=
ResultUtil
.
result
(
ErrorCodes
.
ERROR
,
"hander error"
,
"service error"
,
noUiVersion
.
getVersion
());
}
finally
{
if
(
context
!=
null
)
{
//context.getSupport().disconnect();
context
.
dispose
();
}
}
return
ret
;
}
private
IBaseObject
baseObject
(
NoUiContext
context
,
NoUiRequest
noUiRequest
,
Alias
alias
)
{
String
aliasActionUrl
=
alias
.
getAliasActionUrl
();
String
actionUrl
=
alias
.
getRel
().
get
(
aliasActionUrl
);
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
actionUrl
);
if
(
null
==
baseObject
)
throw
new
NoUiException
(
"onClickUrl :"
+
actionUrl
+
" is not exsit"
);
return
baseObject
;
}
private
Map
<
String
,
Object
>
handleReturnData
(
String
eventType
,
NoUiContext
context
,
NoUiRequest
noUiRequest
,
Alias
alias
)
{
Map
<
String
,
Object
>
data
=
new
HashMap
<
String
,
Object
>();
// 初始化事件
if
(
eventType
.
equals
(
INIT
))
{
for
(
String
aliasKey
:
alias
.
getRel
().
keySet
())
{
if
(
aliasKey
.
startsWith
(
Constants
.
MAPPING_PRE
))
{
continue
;
}
String
realPath
=
alias
.
getRelPath
(
aliasKey
);
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
realPath
);
data
.
put
(
aliasKey
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
baseObject
,
realPath
));
}
return
data
;
}
NoUiPresentation
gui
=
(
NoUiPresentation
)
context
.
getGui
();
Map
<
String
,
Object
>
modifyMap
=
gui
.
getModifyMap
();
List
<
String
>
containsKeys
=
new
ArrayList
<
String
>();
for
(
Map
.
Entry
<
String
,
Object
>
modifyEntry
:
modifyMap
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
String
>
aliasEntry
:
alias
.
getRel
().
entrySet
())
{
String
aliasKey
=
aliasEntry
.
getKey
();
String
aliasPath
=
aliasEntry
.
getValue
();
if
(
aliasPath
==
null
)
{
log
.
error
(
"错误的mapping:"
+
noUiRequest
.
getMappingUrl
()+
"--"
+
aliasKey
+
"--"
+
aliasPath
);
continue
;
}
if
(
modifyEntry
.
getKey
()
==
null
)
{
log
.
error
(
"错误的modifymap:"
+
noUiRequest
.
getMappingUrl
()+
"--"
+
modifyMap
);
continue
;
}
if
(
aliasPath
.
startsWith
(
modifyEntry
.
getKey
()))
{
Object
val
=
modifyEntry
.
getValue
();
if
(
aliasKey
==
null
)
continue
;
data
.
put
(
aliasKey
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
val
,
aliasEntry
.
getValue
()));
containsKeys
.
add
(
modifyEntry
.
getKey
());
}
}
}
// 不能修改
for
(
String
key
:
modifyMap
.
keySet
())
{
if
(!
containsKeys
.
contains
(
key
))
{
System
.
out
.
println
(
"modify test:"
+
modifyMap
.
get
(
key
).
getClass
());
System
.
out
.
println
(
"modify datafield:"
+
(
modifyMap
.
get
(
key
)
instanceof
IDatafield
));
System
.
out
.
println
(
"modify module:"
+
(
modifyMap
.
get
(
key
)
instanceof
IModule
));
System
.
out
.
println
(
"modify moduleList:"
+
(
modifyMap
.
get
(
key
)
instanceof
IModuleList
));
if
(
key
==
null
)
continue
;
data
.
put
(
key
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
modifyMap
.
get
(
key
),
key
));
}
}
return
data
;
}
ret
=
ResultUtil
.
result
(
NoUiPresentationUtil
.
retCode
(
context
),
NoUiPresentationUtil
.
retMsg
(
context
),
afterReturnData
,
NoUiPresentationUtil
.
handleErrorReturnData
(
context
,
alias
),
NoUiPresentationUtil
.
handleCodeTableReturnData
(
context
,
alias
),
noUiVersion
.
getVersion
());
}
catch
(
Exception
e
)
{
log
.
error
(
"OnClick command error"
,
e
);
ret
=
ResultUtil
.
result
(
ErrorCodes
.
ERROR
,
"hander error"
,
"service error"
,
noUiVersion
.
getVersion
());
}
finally
{
if
(
context
!=
null
)
{
//context.getSupport().disconnect();
context
.
dispose
();
}
}
return
ret
;
}
private
IBaseObject
baseObject
(
NoUiContext
context
,
NoUiRequest
noUiRequest
,
Alias
alias
)
{
String
aliasActionUrl
=
alias
.
getAliasActionUrl
();
String
actionUrl
=
alias
.
getRel
().
get
(
aliasActionUrl
);
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
actionUrl
);
if
(
null
==
baseObject
)
throw
new
NoUiException
(
"onClickUrl :"
+
actionUrl
+
" is not exsit"
);
return
baseObject
;
}
private
Map
<
String
,
Object
>
handleReturnData
(
String
eventType
,
NoUiContext
context
,
NoUiRequest
noUiRequest
,
Alias
alias
)
{
Map
<
String
,
Object
>
data
=
new
HashMap
<
String
,
Object
>();
// 初始化事件
if
(
eventType
.
equals
(
INIT
))
{
for
(
String
aliasKey
:
alias
.
getRel
().
keySet
())
{
if
(
aliasKey
.
startsWith
(
Constants
.
MAPPING_PRE
))
{
continue
;
}
String
realPath
=
alias
.
getRelPath
(
aliasKey
);
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
realPath
);
data
.
put
(
aliasKey
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
baseObject
,
realPath
));
}
return
data
;
}
NoUiPresentation
gui
=
(
NoUiPresentation
)
context
.
getGui
();
Map
<
String
,
Object
>
modifyMap
=
gui
.
getModifyMap
();
List
<
String
>
containsKeys
=
new
ArrayList
<
String
>();
for
(
Map
.
Entry
<
String
,
Object
>
modifyEntry
:
modifyMap
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
String
>
aliasEntry
:
alias
.
getRel
().
entrySet
())
{
String
aliasKey
=
aliasEntry
.
getKey
();
String
aliasPath
=
aliasEntry
.
getValue
();
if
(
aliasPath
==
null
)
{
log
.
error
(
"错误的mapping:"
+
noUiRequest
.
getMappingUrl
()
+
"--"
+
aliasKey
+
"--"
+
aliasPath
);
continue
;
}
if
(
modifyEntry
.
getKey
()
==
null
)
{
log
.
error
(
"错误的modifymap:"
+
noUiRequest
.
getMappingUrl
()
+
"--"
+
modifyMap
);
continue
;
}
if
(
aliasPath
.
startsWith
(
modifyEntry
.
getKey
()))
{
Object
val
=
modifyEntry
.
getValue
();
if
(
aliasKey
==
null
)
continue
;
data
.
put
(
aliasKey
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
val
,
aliasEntry
.
getValue
()));
containsKeys
.
add
(
modifyEntry
.
getKey
());
}
}
}
// 不能修改
for
(
String
key
:
modifyMap
.
keySet
())
{
if
(!
containsKeys
.
contains
(
key
))
{
System
.
out
.
println
(
"modify test:"
+
modifyMap
.
get
(
key
).
getClass
());
System
.
out
.
println
(
"modify datafield:"
+
(
modifyMap
.
get
(
key
)
instanceof
IDatafield
));
System
.
out
.
println
(
"modify module:"
+
(
modifyMap
.
get
(
key
)
instanceof
IModule
));
System
.
out
.
println
(
"modify moduleList:"
+
(
modifyMap
.
get
(
key
)
instanceof
IModuleList
));
if
(
key
==
null
)
continue
;
data
.
put
(
key
,
NoUiPresentationUtil
.
handIBaseObject
(
context
,
modifyMap
.
get
(
key
),
key
));
}
}
return
data
;
}
}
src/main/java/org/sss/presentation/noui/util/DataSecurityUtil.java
View file @
98654e0b
...
...
@@ -6,6 +6,8 @@ import org.apache.commons.lang.ArrayUtils;
import
org.springframework.core.io.ClassPathResource
;
import
org.sss.common.model.IBaseObject
;
import
org.sss.common.model.IDatafield
;
import
org.sss.common.model.IModule
;
import
org.sss.common.model.IModuleList
;
import
org.sss.presentation.noui.common.Constants
;
import
org.sss.presentation.noui.context.NoUiContext
;
...
...
@@ -16,72 +18,123 @@ import java.util.*;
* 使用动态盐机制,每个盐只做一次双向校验后就失效
*/
public
class
DataSecurityUtil
{
public
static
final
String
ENCRYPT_FIX
=
"_encode"
;
public
static
final
String
DECRYPT_FIX
=
"_decode"
;
public
static
final
String
ENCRYPT_ERROR
=
"encrypt exception"
;
public
static
final
String
DECRYPT_ERROR
=
"decrypt exception"
;
public
static
final
String
BACKGROUND_ID
=
"__bgid__"
;
public
static
final
String
ERROR_SERVERENC_NULL
=
"[服务端密文串异常],数据存在篡改风险!"
;
public
static
final
String
ERROR_DYNAMICSALT_NULL
=
"[获取的动态盐不存在],可能存在后台暴力破解风险,从而导致数据存在篡改被篡改的风险!"
;
public
static
final
String
ERROR_DYNAMICSALT_EXCEPTION
=
"[获取动态盐异常],可能redis异常,从而导致数据存在篡改被篡改的风险!"
;
public
static
final
String
ERROR_AES_DECODE
=
"[服务端密文串解密失败],数据存在篡改风险!"
;
public
static
final
String
ERROR_NOTMATCH
=
"[服务端密文串解密后的值与客户端密文串不同],数据存在篡改风险!"
;
public
static
final
String
SWITCH_KEY
=
"switch"
;
public
static
final
String
SAFE_MODE
=
"ON"
;
public
static
final
String
UNSAFE_MODE
=
"OFF"
;
private
static
HashMap
<
String
,
String
>
securityConfig
;
public
static
final
String
BACKGROUND_ID
=
"__bgid__"
;
public
static
final
String
ERROR_SERVERENC_NULL
=
"[服务端密文串异常],数据存在篡改风险!"
;
public
static
final
String
ERROR_DYNAMICSALT_NULL
=
"[获取的动态盐不存在],可能存在后台暴力破解风险,从而导致数据存在篡改被篡改的风险!"
;
public
static
final
String
ERROR_DYNAMICSALT_EXCEPTION
=
"[获取动态盐异常],可能redis异常,从而导致数据存在篡改被篡改的风险!"
;
public
static
final
String
ERROR_AES_DECODE
=
"[服务端密文串解密失败],数据存在篡改风险!"
;
public
static
final
String
ERROR_NOTMATCH
=
"[服务端密文串解密后的值与客户端密文串不同],数据存在篡改风险!"
;
private
static
final
Log
log
=
LogFactory
.
getLog
(
DataSecurityUtil
.
class
);
public
static
boolean
SWITCH
=
false
;
private
static
HashMap
<
String
,
String
[]>
securityConfig
=
new
HashMap
<
String
,
String
[]>();
static
{
ClassPathResource
resource
=
new
ClassPathResource
(
"security.properties"
,
DataSecurityUtil
.
class
);
static
{
ClassPathResource
resource
=
new
ClassPathResource
(
"security.properties"
,
DataSecurityUtil
.
class
);
try
{
securityConfig
=
new
HashMap
<
String
,
String
>((
Map
)
PropertyUtil
.
load
(
"security.properties"
));
Map
<
String
,
String
>
tmp
=
new
HashMap
<
String
,
String
>((
Map
)
PropertyUtil
.
load
(
"security.properties"
));
for
(
Map
.
Entry
<
String
,
String
>
entry
:
tmp
.
entrySet
())
{
String
key
=
entry
.
getKey
();
String
val
=
entry
.
getValue
();
if
(
"switch"
.
equals
(
key
)
&&
"ON"
.
equals
(
val
))
{
SWITCH
=
true
;
}
else
{
//数据安全配置
if
(
securityConfig
.
containsKey
(
key
))
{
log
.
warn
(
"忽略重复的安全信息:"
+
key
);
continue
;
}
if
(
StringUtil
.
isEmpty
(
val
))
{
log
.
warn
(
"忽略值为空的安全信息:"
+
key
);
continue
;
}
securityConfig
.
put
(
key
,
val
.
split
(
";"
));
}
}
}
catch
(
Exception
e
)
{
//降级处理
log
.
warn
(
"加载安全配置文件失败:"
+
e
.
getMessage
())
;
securityConfig
=
new
HashMap
<
String
,
String
>();
securityConfig
.
put
(
SWITCH_KEY
,
UNSAFE_MODE
);
SWITCH
=
false
;
securityConfig
=
new
HashMap
<
String
,
String
[]
>();
log
.
warn
(
"加载安全配置文件失败:"
+
e
.
getMessage
()
);
}
}
/**
* 是否开启安全模式,开启后会对前端传输的数据根据配置文件做篡改性校验
*
* @return true表示开启;false不开启
*/
public
static
boolean
isSafeMode
(){
return
SAFE_MODE
.
equalsIgnoreCase
(
securityConfig
.
get
(
SWITCH_KEY
));
public
static
boolean
isSafeMode
()
{
return
SWITCH
;
}
public
static
boolean
needEncrypt
(
String
reqUrl
)
{
return
securityConfig
.
containsKey
(
reqUrl
+
ENCRYPT_FIX
);
}
public
static
boolean
needDecrypt
(
String
reqUrl
)
{
return
securityConfig
.
containsKey
(
reqUrl
+
DECRYPT_FIX
);
}
/**
* 获取指定交易的安全配置
* @param context 交易上下文
* @param trnName 交易名
*
* @param context 交易上下文
* @param configKey 安全配置的key
* @return 指定交易的安全配置信息
*/
public
static
String
[]
getSafeConfigByTrnName
(
NoUiContext
context
,
String
trnName
){
String
safeConfigByTrnName
=
securityConfig
.
get
(
trnName
);
if
(!
StringUtil
.
isEmpty
(
safeConfigByTrnName
)){
String
[]
urls
=
safeConfigByTrnName
.
split
(
","
);
String
[]
pars
=
new
String
[
urls
.
length
];
for
(
int
i
=
0
;
i
<
urls
.
length
;
i
++){
String
url
=
urls
[
i
];
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
url
);
if
(
null
==
baseObject
)
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"交易["
).
append
(
trnName
).
append
(
"]对应的待校验字段["
);
sb
.
append
(
url
).
append
(
"]在模型中未找到"
);
log
.
error
(
sb
.
toString
());
}
else
{
if
(
baseObject
instanceof
IDatafield
<?>)
{
IDatafield
<
Object
>
dataField
=
(
IDatafield
<
Object
>)
baseObject
;
pars
[
i
]=
dataField
.
getValue
().
toString
();
}
else
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"交易["
).
append
(
trnName
).
append
(
"]对应的待校验字段["
);
sb
.
append
(
url
).
append
(
"]在模型中不是IDatafield类型"
);
log
.
error
(
sb
.
toString
());
public
static
String
[]
getSafeConfigByReqUrl
(
NoUiContext
context
,
String
configKey
)
{
String
[]
safeConfigByTrnNames
=
securityConfig
.
get
(
configKey
);
for
(
String
safeConfigByTrnName
:
safeConfigByTrnNames
)
{
if
(!
StringUtil
.
isEmpty
(
safeConfigByTrnName
))
{
String
[]
urls
=
safeConfigByTrnName
.
split
(
","
);
String
[]
pars
=
new
String
[
urls
.
length
];
boolean
flag
=
true
;
for
(
int
i
=
0
;
i
<
urls
.
length
;
i
++)
{
String
url
=
urls
[
i
];
String
lstTemplate
=
null
;
if
(
url
.
indexOf
(
"[]"
)>
0
){
lstTemplate
=
url
;
url
=
url
.
substring
(
0
,
url
.
indexOf
(
"[]"
));
}
IBaseObject
baseObject
=
context
.
getSession
().
getBaseObject
(
context
.
getRoot
(),
url
);
if
(
null
==
baseObject
)
{
flag
=
false
;
break
;
}
else
{
if
(
baseObject
instanceof
IDatafield
<?>)
{
IDatafield
<
Object
>
dataField
=
(
IDatafield
<
Object
>)
baseObject
;
String
val
=
dataField
.
getValue
().
toString
();
pars
[
i
]
=
val
;
}
else
if
(
baseObject
instanceof
IModuleList
<?>)
{
IModuleList
<?>
moduleList
=
(
IModuleList
<?>)
baseObject
;
String
[]
checkList
=
new
String
[
moduleList
.
size
()];
for
(
int
index
=
0
;
index
<
moduleList
.
size
();
index
++)
{
IModule
module
=
moduleList
.
get
(
index
);
String
npth
=
lstTemplate
.
replace
(
"[]"
,
"["
+
index
+
"]"
);
IDatafield
<
Object
>
dataField
=
(
IDatafield
<
Object
>)
context
.
getSession
().
getBaseObject
(
module
,
npth
);
String
val
=
dataField
.
getValue
().
toString
();
checkList
[
index
]=
val
;
}
pars
[
i
]=
String
.
join
(
"_"
,
checkList
);
}
else
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"安全配置["
).
append
(
configKey
).
append
(
"]对应的待校验字段["
);
sb
.
append
(
url
).
append
(
"]在模型中不是IDatafield类型"
);
log
.
error
(
sb
.
toString
());
}
}
}
if
(
flag
)
{
return
pars
;
}
}
return
pars
;
}
return
null
;
}
...
...
@@ -110,50 +163,66 @@ public class DataSecurityUtil {
/**
* 判断数据是否篡改
*
* @param serverEnc 服务端产生的密文串
* @param serverEnc
服务端产生的密文串
* @param clientpars 客户端待校验参数
* @param userId 用户id
* @param userId
用户id
* @return 返回错误描述
*/
public
static
String
checkIllegalData
(
String
serverEnc
,
String
[]
clientpars
,
String
userId
)
{
//1.判断服务端的密文串是否异常
if
(
StringUtil
.
isEmpty
(
serverEnc
)
||
ENCRYPT_ERROR
.
equals
(
serverEnc
))
{
if
(
StringUtil
.
isEmpty
(
serverEnc
)
||
ENCRYPT_ERROR
.
equals
(
serverEnc
))
{
log
.
warn
(
ERROR_SERVERENC_NULL
);
return
ERROR_SERVERENC_NULL
;
}
//2.用aes动态盐解密服务端密文串与客户端的密文串比对
DynamicSalt
dynamicSalt
;
try
{
dynamicSalt
=
getDynamicSaltFromRedis
(
userId
);
if
(
dynamicSalt
==
null
)
{
dynamicSalt
=
getDynamicSaltFromRedis
(
userId
);
if
(
dynamicSalt
==
null
)
{
log
.
warn
(
ERROR_DYNAMICSALT_NULL
);
return
ERROR_DYNAMICSALT_NULL
;
}
}
catch
(
Exception
e
)
{
log
.
warn
(
ERROR_DYNAMICSALT_EXCEPTION
+
e
.
getMessage
());
log
.
warn
(
ERROR_DYNAMICSALT_EXCEPTION
+
e
.
getMessage
());
return
ERROR_DYNAMICSALT_EXCEPTION
;
}
serverEnc
=
decrypt
(
serverEnc
,
dynamicSalt
);
if
(
StringUtil
.
isEmpty
(
serverEnc
)
||
DECRYPT_ERROR
.
equals
(
serverEnc
)){
serverEnc
=
decrypt
(
serverEnc
,
dynamicSalt
);
if
(
StringUtil
.
isEmpty
(
serverEnc
)
||
DECRYPT_ERROR
.
equals
(
serverEnc
))
{
log
.
warn
(
ERROR_AES_DECODE
);
return
ERROR_AES_DECODE
;
}
String
clientEnc
=
preHandle
(
clientpars
);
if
(!
serverEnc
.
equals
(
clientEnc
)){
String
clientEnc
=
preHandle
(
clientpars
);
if
(
serverEnc
.
indexOf
(
"_"
)>
0
){
//集合处理
String
[]
parts
=
serverEnc
.
split
(
","
);
for
(
String
part:
parts
){
if
(!
StringUtil
.
isEmpty
(
part
)){
for
(
String
item:
part
.
split
(
"_"
)){
if
(
item
.
equals
(
clientEnc
)){
return
null
;
}
}
}
}
log
.
warn
(
ERROR_NOTMATCH
);
return
ERROR_NOTMATCH
;
}
else
{
if
(!
serverEnc
.
equals
(
clientEnc
))
{
log
.
warn
(
ERROR_NOTMATCH
);
return
ERROR_NOTMATCH
;
}
}
try
{
RedisUtil
.
delete
(
getCacheSaltKey
(
userId
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除失效盐出现异常:"
+
e
.
getMessage
());
log
.
warn
(
"删除失效盐出现异常:"
+
e
.
getMessage
());
}
return
null
;
}
/**
* 获取指定用户缓存盐的key
*
* @param userId 用户ID
* @return 返回指定用户缓存盐的key
*/
...
...
@@ -167,32 +236,32 @@ public class DataSecurityUtil {
return
content
==
null
?
DECRYPT_ERROR
:
content
;
}
private
static
String
preHandle
(
String
[]
pars
){
private
static
String
preHandle
(
String
[]
pars
)
{
if
(
ArrayUtils
.
isEmpty
(
pars
))
{
return
null
;
}
List
<
String
>
lst
=
Arrays
.
asList
(
pars
);
String
md5
=
String
.
join
(
"
"
,
lst
);
String
md5
=
String
.
join
(
",
"
,
lst
);
return
md5
;
}
private
static
DynamicSalt
getDynamicSaltFromRedis
(
String
userId
)
throws
Exception
{
String
key
=
getCacheSaltKey
(
userId
);
String
key
=
getCacheSaltKey
(
userId
);
Object
obj
=
RedisUtil
.
get
(
key
);
DynamicSalt
rs
=
parseDynamicSalt
(
obj
);
if
(
rs
!=
null
)
{
DynamicSalt
rs
=
parseDynamicSalt
(
obj
);
if
(
rs
!=
null
)
{
return
rs
;
}
return
null
;
}
private
static
DynamicSalt
parseDynamicSalt
(
Object
raw
){
if
(
raw
instanceof
String
)
{
String
[]
parts
=
((
String
)
raw
).
split
(
"_"
);
if
(
parts
!=
null
&&
parts
.
length
==
2
)
{
return
new
DynamicSalt
(
parts
[
0
],
parts
[
1
]);
private
static
DynamicSalt
parseDynamicSalt
(
Object
raw
)
{
if
(
raw
instanceof
String
)
{
String
[]
parts
=
((
String
)
raw
).
split
(
"_"
);
if
(
parts
!=
null
&&
parts
.
length
==
2
)
{
return
new
DynamicSalt
(
parts
[
0
],
parts
[
1
]);
}
}
else
if
(
raw
instanceof
DynamicSalt
)
{
}
else
if
(
raw
instanceof
DynamicSalt
)
{
return
(
DynamicSalt
)
raw
;
}
return
null
;
...
...
@@ -222,7 +291,7 @@ public class DataSecurityUtil {
@Override
public
String
toString
()
{
return
iv
+
"_"
+
pwd
;
return
iv
+
"_"
+
pwd
;
}
}
}
src/main/resources/security.properties
View file @
98654e0b
#安全开关(ON:开;OFF:关)
switch
=
ON
#客户管理——查询
/dblpty/
sel_encode
=
\\
ptyp
\\
ptylst[]
\\
inr
#客户管理——修改
dbepty
=
\\
ptygrp
\\
rec
\\
inr,
\\
ptygrp
\\
rec
\\
extkey
/dbepty/
init_decode
=
\\
ptygrp
\\
rec
\\
inr
/dbepty/
init_encode
=
\\
ptygrp
\\
rec
\\
inr,
\\
ptygrp
\\
rec
\\
extkey
/dbepty/
sav_decode
=
\\
ptygrp
\\
rec
\\
inr,
\\
ptygrp
\\
rec
\\
extkey
#客户管理——删除
dbdpty
=
\\
ptygrp
\\
rec
\\
inr
/dbdpty/
init_decode
=
\\
ptygrp
\\
rec
\\
inr
/dbdpty/
init_encode
=
\\
ptygrp
\\
rec
\\
inr
/dbdpty/
sav_decode
=
\\
ptygrp
\\
rec
\\
inr
#
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment