Browse Source

提交demo代码

10.0
LAPTOP-SB56SG4Q\86185 4 years ago
parent
commit
cb6147bea4
  1. 4
      README.md
  2. 124
      build.gradle
  3. 13
      encrypt.xml
  4. 20
      plugin.xml
  5. 103
      src/main/java/com/tptj/demo/hg/parameter/decode/DecodeRequest.java
  6. 121
      src/main/java/com/tptj/demo/hg/parameter/decode/Demo1.java
  7. 35
      src/main/java/com/tptj/demo/hg/parameter/decode/Demo2.java
  8. 65
      src/main/java/com/tptj/demo/hg/parameter/decode/Sign.java

4
README.md

@ -1,3 +1,5 @@
# demo-parameter-decode
参数解密demo示例
参数解密demo示例\
参数加密传输场景中的,通过签名算法保障参数表不被篡改和有效期控制的方案示例代码\
plugin.xml中两个接口实际使用时只需要选择其中一个即可。

124
build.gradle

@ -0,0 +1,124 @@
apply plugin: 'java'
[compileJava,compileTestJava]*.options*.encoding = 'UTF-8'
ext {
/**
* jar的路径
* 1.jar需要打包到zip中,lib根目录下
* 2.jar仅仅是编译时需要lib下子目录下即可
*/
libPath = "$projectDir/../../webroot/WEB-INF/lib"
/**
* class进行加密保护
*/
guard = false
def pluginInfo = getPluginInfo()
pluginPre = "fine-plugin"
pluginName = pluginInfo.id
pluginVersion = pluginInfo.version
outputPath = "$projectDir/../../webroot/WEB-INF/plugins/plugin-" + pluginName + "-1.0/classes"
}
group = 'com.fr.plugin'
version = '10.0'
sourceCompatibility = '8'
sourceSets {
main {
java.outputDir = file(outputPath)
output.resourcesDir = file(outputPath)
}
}
ant.importBuild("encrypt.xml")
//ant变量
ant.projectDir = projectDir
ant.references["compile.classpath"] = ant.path {
fileset(dir: libPath, includes: '**/*.jar')
fileset(dir: ".",includes:"**/*.jar" )
}
classes.dependsOn('clean')
task copyFiles(type: Copy,dependsOn: 'classes'){
from outputPath
into "$projectDir/classes"
}
task preJar(type:Copy,dependsOn: guard ? 'compile_encrypt_javas' : 'compile_plain_javas'){
from "$projectDir/classes"
into "$projectDir/transform-classes"
include "**/*.*"
}
jar.dependsOn("preJar")
task makeJar(type: Jar,dependsOn: preJar){
from fileTree(dir: "$projectDir/transform-classes")
baseName pluginPre
appendix pluginName
version pluginVersion
destinationDir = file("$buildDir/libs")
doLast(){
delete file("$projectDir/classes")
delete file("$projectDir/transform-classes")
}
}
task copyFile(type: Copy,dependsOn: ["makeJar"]){
from "$buildDir/libs"
from("$projectDir/lib") {
include "*.jar"
}
from "$projectDir/plugin.xml"
into file("$buildDir/temp/plugin")
}
task zip(type:Zip,dependsOn:["copyFile"]){
from "$buildDir/temp/plugin"
destinationDir file("$buildDir/install")
baseName pluginPre
appendix pluginName
version pluginVersion
}
//build时包含哪些文件,
processResources {
// exclude everything
// *.css没效果
// exclude '**/*.css'
// except this file
// include 'xx.xml'
}
/*读取plugin.xml中的version*/
def getPluginInfo(){
def xmlFile = file("plugin.xml")
if (!xmlFile.exists()) {
return ["id":"none", "version":"1.0.0"]
}
def plugin = new XmlParser().parse(xmlFile)
def version = plugin.version[0].text()
def id = plugin.id[0].text()
return ["id":id,"version":version]
}
repositories {
mavenLocal()
maven {
url = uri('http://mvn.finedevelop.com/repository/maven-public/')
}
}
dependencies {
//使jar
implementation fileTree(dir: 'lib', include: ['**/*.jar'])
implementation fileTree(dir: libPath, include: ['**/*.jar'])
}

13
encrypt.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<target name="compile_encrypt_javas" depends="copyFiles">
<echo message="加密文件"/>
<echo message="${projectDir}"/>
<taskdef name="pretreatment" classname="com.fr.plugin.pack.PluginPretreatmentTask">
<classpath refid="compile.classpath"/>
</taskdef>
<pretreatment baseDir="${projectDir}"/>
</target>
<target name="compile_plain_javas" depends="copyFiles">
</target>
</project>

20
plugin.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.tptj.demo.hg.parameter.decode.v10</id>
<name><![CDATA[ Parameter Decode ]]></name>
<active>yes</active>
<version>1.0</version>
<env-version>10.0</env-version>
<vendor>tptj</vendor>
<jartime>2019-07-18</jartime>
<description><![CDATA[ ]]></description>
<change-notes><![CDATA[]]></change-notes>
<main-package>com.tptj.demo.hg.parameter.decode</main-package>
<function-recorder class="com.tptj.demo.hg.parameter.decode.Sign"/>
<!-- 以下两个接口实际使用时只需要选择其中一个即可,两个同时使用会产生冲突! -->
<extra-core>
<RequestParameterHandler class="com.tptj.demo.hg.parameter.decode.Demo1"/>
</extra-core>
<extra-decision>
<GlobalRequestFilterProvider class="com.tptj.demo.hg.parameter.decode.Demo2"/>
</extra-decision>
</plugin>

103
src/main/java/com/tptj/demo/hg/parameter/decode/DecodeRequest.java

@ -0,0 +1,103 @@
package com.tptj.demo.hg.parameter.decode;
import com.fr.data.DefaultRequestParameterHandler;
import com.fr.stable.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
/**
* @author 秃破天际
* @version 10.0
* Created by 秃破天际 on 2021/7/11
**/
public class DecodeRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
public DecodeRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 存放验签的结果
*/
private boolean result = true;
/**
* 受保护的参数表
*/
private Set<String> parameter_names = new TreeSet<String>();
private Map<String, String[]> parameters= new HashMap<String, String[]>();
private Object getSuperValue(String name){
Object val = super.getHeader(name);
if( null != val ){
return val;
}
val = super.getParameter(name);
if( null != val ){
return val;
}
return new DefaultRequestParameterHandler().getParameterFromJSONParameters(request,name);
}
private void init(){
parameter_names = Demo1.getTagNames( (HttpServletRequest)getRequest() );
String sign_str = (String) getSuperValue( "sign");
Sign sign = Sign.parse(sign_str);
//过有效期
if( sign.isTimeout() ){
result = false;
}else{
StringBuilder sb = new StringBuilder();
for( String pname : parameter_names ){
Object val = getSuperValue(pname);
if( null != val){
sb.append(pname).append(val);
}
}
result = sign.check( sb.toString(), Demo1.SECRET );
}
//调整参数表
Set<Map.Entry<String, String[]>> entries = getParameterMap().entrySet();
for( Map.Entry<String, String[]> entry : entries ){
String key = entry.getKey();
String[] value = entry.getValue();
//验签失败的情况下,所有的涉敏参数都要设置成空的
if( !result && parameter_names.contains(key) ){
parameters.put( key, new String[]{StringUtils.EMPTY});
}else{
parameters.put( key, value);
}
}
}
@Override
public String getParameter(String name){
if( parameters.containsKey(name) ){
return parameters.get(name)[0];
}
return null;
}
@Override
public String getHeader(String name){
if( !result && parameter_names.contains(name) ){
return StringUtils.EMPTY;
}
return super.getHeader(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return parameters;
}
@Override
public String[] getParameterValues(String name) {
return parameters.get(name);
}
}

121
src/main/java/com/tptj/demo/hg/parameter/decode/Demo1.java

@ -0,0 +1,121 @@
package com.tptj.demo.hg.parameter.decode;
import com.fr.base.BaseUtils;
import com.fr.data.DefaultRequestParameterHandler;
import com.fr.general.data.DataModel;
import com.fr.script.Calculator;
import com.fr.stable.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;
import java.util.TreeSet;
/**
* @author 秃破天际
* @version 10.0
* Created by 秃破天际 on 2021/7/11
* MD5签名的参数获取方案校验注意该代码仅仅是教学演示用
* 并非完整可靠的方案要实际运用在项目中要自行根据项目需要进行相应改造
**/
public class Demo1 extends DefaultRequestParameterHandler {
public static final String DS_NAME = "ProtectedParameterNames";
/**
* 假设密钥固定是123456实际开发时可用配置的方式实现
*/
public static final String SECRET = "123456";
/**
* 假设有一个服务器数据集名字叫ProtectedParameterNames数据集第一列就是一组参数名里面所有的参数都禁止用户自己选择和传递
* @param req
* @return
*/
public static Set<String> getTagNames(HttpServletRequest req){
Set<String> set = (Set<String>)req.getSession(true).getAttribute(DS_NAME);
if( null != set ){
return set;
}
//需要排序
set = new TreeSet<String>();
try{
DataModel dm = BaseUtils.getDataModelFromTableDataName(Calculator.createCalculator(), DS_NAME);
for(int i=0,len=dm.getRowCount(); i<len; i++){
set.add( (String)dm.getValueAt(i,0) );
}
req.getSession(true).setAttribute(DS_NAME,set);
}catch(Exception e){
}
return set;
}
/**
* 获取请求原始携带的参数
* @param req
* @param name
* @return
*/
public Object getSuperValue(HttpServletRequest req,String name){
Object val = super.getParameterFromHeader(req,name);
if( null != val ){
return val;
}
val = super.getParameterFromRequest(req,name);
if( null != val ){
return val;
}
return super.getParameterFromJSONParameters(req,name);
}
private Object getResult(HttpServletRequest req,String name, Object value ){
Set<String> pnames = getTagNames(req);
if( !pnames.contains(name) ){
return value;
}
String sign_str = (String) getSuperValue(req, "sign");
Sign sign = Sign.parse(sign_str);
//过有效期
if( sign.isTimeout() ){
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
for( String pname : pnames ){
Object val = getSuperValue(req,pname);
if( null != val){
sb.append(pname).append(val);
}
}
//签名不合法
if( !sign.check( sb.toString(), SECRET ) ){
return StringUtils.EMPTY;
}
return value;
}
@Override
public Object getParameterFromRequest(HttpServletRequest req, String name) {
Object value = super.getParameterFromRequest(req,name);
return getResult(req,name,value);
}
@Override
public Object getParameterFromHeader(HttpServletRequest req, String name) {
Object value = super.getParameterFromHeader(req,name);
return getResult(req,name,value);
}
@Override
public Object getParameterFromJSONParameters(HttpServletRequest req, String name){
//FR在设计的时候,参数不仅仅可以直接在query中通过参数名直接给到,还可以通过 __parameters__ 给到一个json字符串来提个一个额外的参数表
//同一个参数名的参数优先级 header > query > attribute > json > session
Object value = super.getParameterFromJSONParameters(req,name);
return getResult(req,name,value);
}
@Override
public Object getParameterFromRequestInputStream(HttpServletRequest req, String name){
//这里单独实现这个方法是强调一下,在10.0版本中,该方法已经没有用了。开发者不要考虑通过这个方法从body中抽取参数
//如果要使用这个方法,就需要使用filter先把请求的input stream 改成可重复读取的。否则平台请求会报错!
//但是如果都用filter去处理参数了,我们就完全没必要使用这个接口了。
return super.getParameterFromRequestInputStream(req,name);
}
}

35
src/main/java/com/tptj/demo/hg/parameter/decode/Demo2.java

@ -0,0 +1,35 @@
package com.tptj.demo.hg.parameter.decode;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author 秃破天际
* @version 10.0
* Created by 秃破天际 on 2021/7/11
**/
public class Demo2 extends AbstractGlobalRequestFilterProvider {
@Override
public String filterName() {
return "Parameter Decode";
}
@Override
public String[] urlPatterns() {
return new String[]{
"/*"
};
}
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
req = new DecodeRequest(req);
try{
chain.doFilter(req, res);
}catch (Exception e){
}
}
}

65
src/main/java/com/tptj/demo/hg/parameter/decode/Sign.java

@ -0,0 +1,65 @@
package com.tptj.demo.hg.parameter.decode;
import com.fr.intelli.record.Focus;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.stable.CodeUtils;
import com.fr.stable.StringUtils;
/**
* @author 秃破天际
* @version 10.0
* Created by 秃破天际 on 2021/7/11
**/
@EnableMetrics
public class Sign {
private String md5;
private long timestamp;
private long timeout;
private Sign(String md5, long timestamp, long timeout) {
this.md5 = md5;
this.timestamp = timestamp;
this.timeout = timeout;
}
private final static Sign EMPTY = new Sign(StringUtils.EMPTY,0,0);
/**
* 解析签名
* @param sign
* @return
*/
public static Sign parse( String sign ){
try{
String md5 = sign.substring(0,32);
long timestamp = Long.parseLong( sign.substring(33,46) );
long timeout = Long.parseLong( sign.substring(47) );
return new Sign(md5,timestamp,timeout);
}catch(Exception e){
}
return EMPTY;
}
/**
* 检验超时
* @return
*/
public boolean isTimeout(){
long crt = System.currentTimeMillis();
return crt < timestamp || crt - timestamp > timeout;
}
/**
* 验签
* @param data
* @param secret
* @return
*/
@Focus(id = "com.tptj.demo.hg.parameter.decode.v10",text = "Parameter Decode")
public boolean check( String data, String secret ){
String source = data+secret+timestamp+timeout;
String md5 = CodeUtils.md5Encode(source, StringUtils.EMPTY,"MD5");
return StringUtils.equals(md5,this.md5);
}
}
Loading…
Cancel
Save