commit
3bbd60c3f0
24 changed files with 1381 additions and 0 deletions
@ -0,0 +1,7 @@
|
||||
|
||||
# open-JSD-9826 |
||||
|
||||
JSD-9826 BI与客户系统集成,实现4A单点登录认证\ |
||||
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||
仅作为开发者学习参考使用!禁止用于任何商业用途!\ |
||||
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 |
@ -0,0 +1,121 @@
|
||||
|
||||
apply plugin: 'java' |
||||
|
||||
|
||||
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']) |
||||
} |
Binary file not shown.
@ -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> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<plugin> |
||||
<id>com.fr.plugin.foauth.login</id> |
||||
<name><![CDATA[4a单点登录插件]]></name> |
||||
<active>yes</active> |
||||
<version>1.0.1</version> |
||||
<env-version>10.0</env-version> |
||||
<jartime>2020-07-31</jartime> |
||||
<vendor>fr.open</vendor> |
||||
<description> |
||||
1.0.1- 新增登录成功后重定向功能 |
||||
</description> |
||||
|
||||
<lifecycle-monitor class="com.fr.plugin.FLLifeCycleMonitor"/> |
||||
<extra-decision> |
||||
<!-- <PassportProvider class="com.fr.plugin.FLPassportProvider"/>--> |
||||
<!-- <WebResourceProvider class="com.fr.plugin.LogindJSHandler"/>--> |
||||
<!-- 长连接 --> |
||||
<HttpHandlerProvider class="com.fr.plugin.FLHttpHander"/> |
||||
<!-- 短连接 --> |
||||
<URLAliasProvider class="com.fr.plugin.FLURLAliasBridge"/> |
||||
</extra-decision> |
||||
<function-recorder class="com.fr.plugin.FLURLAliasBridge"/> |
||||
</plugin> |
@ -0,0 +1,196 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fanruan.api.data.ConnectionKit; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.log.FineLoggerProvider; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.sql.*; |
||||
import java.util.*; |
||||
|
||||
public class DBUtils { |
||||
String db_name = ""; |
||||
|
||||
private static FineLoggerProvider logger = FineLoggerFactory.getLogger(); |
||||
|
||||
public DBUtils(String db_name) { |
||||
this.db_name = db_name; |
||||
} |
||||
|
||||
public DBUtils() { |
||||
this.db_name = "FRDW"; |
||||
} |
||||
|
||||
public com.fr.data.impl.Connection getDbConnect() { |
||||
return ConnectionKit.getConnection(db_name); |
||||
} |
||||
|
||||
public List<Map<String, Object>> select(String sql, Object... params) { |
||||
logger.info("query data by sql:" + sql + Arrays.toString(params)); |
||||
try { |
||||
com.fr.data.impl.Connection dbConnect = getDbConnect(); |
||||
Connection con = dbConnect.createConnection(); |
||||
PreparedStatement preparedStatement = con.prepareStatement(sql); |
||||
setParams(preparedStatement, params); |
||||
ResultSet rs = preparedStatement.executeQuery(sql); |
||||
// 获得记录的详细信息,然后获得总列数
|
||||
ResultSetMetaData resMetaData = rs.getMetaData(); |
||||
int colNum = resMetaData.getColumnCount(); |
||||
// 用对象保存数据
|
||||
String name = ""; |
||||
String value = ""; |
||||
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); |
||||
while (rs.next()) { |
||||
Map<String, Object> cells = new HashMap<String, Object>(); |
||||
for (int i = 0; i < colNum; i++) { |
||||
name = resMetaData.getColumnLabel(i); |
||||
if (cells.get(name) != null) { |
||||
name = resMetaData.getColumnLabel(i); |
||||
} |
||||
if (rs.getObject(i) != null && resMetaData.getColumnTypeName(i).equals("DATETIME") || resMetaData.getColumnTypeName(i).equals("TIMESTAMP")) { |
||||
value = rs.getObject(i).toString(); |
||||
cells.put(name, value.substring(0, value.length() - 2)); |
||||
} else { |
||||
cells.put(name, rs.getString(i)); |
||||
} |
||||
} |
||||
list.add(cells); |
||||
} |
||||
// 释放数据库资源
|
||||
rs.close(); |
||||
preparedStatement.close(); |
||||
con.close(); |
||||
return list; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public int exec(String sql, String date) throws Exception { |
||||
logger.info("query data by sql:{} 时间:{}", sql, date); |
||||
Connection con = null; |
||||
CallableStatement call = null; |
||||
try { |
||||
com.fr.data.impl.Connection dbConnect = getDbConnect(); |
||||
con = dbConnect.createConnection(); |
||||
call = con.prepareCall(sql); |
||||
call.registerOutParameter(1, Types.INTEGER); |
||||
call.execute(); |
||||
Integer ret = call.getInt(1); |
||||
return ret; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
throw e; |
||||
} finally { |
||||
if (call != null) { |
||||
call.close(); |
||||
} |
||||
if (con != null) { |
||||
con.close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public Map<String, Object> findOneRow(String sql, Object... params) { |
||||
List<Map<String, Object>> select = select(sql, params); |
||||
if (select != null) { |
||||
if (!select.isEmpty()) { |
||||
return select.get(0); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public boolean checkExist(String sql, Object... params) throws Exception { |
||||
Connection connection = getDbConnect().createConnection(); |
||||
PreparedStatement pstmt = connection.prepareStatement(sql); |
||||
setParams(pstmt, params); |
||||
try { |
||||
ResultSet resultSet = pstmt.executeQuery(); |
||||
if (resultSet.next()) { |
||||
return resultSet.getInt(1) > 0; |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} finally { |
||||
connection.close(); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private void setParams(PreparedStatement pstmt, Object... params) throws SQLException { |
||||
if (params.length > 0) { |
||||
int length = params.length; |
||||
for (int i = 1; i <= length; i++) { |
||||
pstmt.setObject(i, params[i - 1]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public int exSqlUpdate(String sql, Object... params) throws Exception { |
||||
logger.info("update data by sql:" + sql + " params " + Arrays.toString(params)); |
||||
PreparedStatement pstmt = null; |
||||
Connection connection = null; |
||||
try { |
||||
com.fr.data.impl.Connection dbConnect = getDbConnect(); |
||||
connection = dbConnect.createConnection(); |
||||
pstmt = connection.prepareStatement(sql); |
||||
setParams(pstmt, params); |
||||
int i = pstmt.executeUpdate(); |
||||
return i; |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("执行更新SQL报错: sql:{}", e, sql); |
||||
} finally { |
||||
if (pstmt != null) { |
||||
pstmt.close(); |
||||
} |
||||
if (connection != null) { |
||||
connection.close(); |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/** |
||||
* 取查询结果集字段 |
||||
* |
||||
* @param sql |
||||
* @param params |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
public List<Map<String, String>> exQuery(String sql, Object... params) throws Exception { |
||||
logger.info("query data by sql:" + sql + " params " + Arrays.toString(params)); |
||||
com.fr.data.impl.Connection dbConnect = getDbConnect(); |
||||
Connection connection = dbConnect.createConnection(); |
||||
PreparedStatement pstmt = connection.prepareStatement(sql); |
||||
setParams(pstmt, params); |
||||
ResultSet resultSet = pstmt.executeQuery(); |
||||
ResultSetMetaData resMetaData = resultSet.getMetaData(); |
||||
int columnCount = resMetaData.getColumnCount(); |
||||
List<Map<String, String>> arrs = new ArrayList<Map<String, String>>(); |
||||
while (resultSet.next()) { |
||||
String name; |
||||
String value; |
||||
Map<String, String> one = new HashMap<String, String>(); |
||||
for (int i = 1; i <= columnCount; i++) { |
||||
name = resMetaData.getColumnLabel(i); |
||||
if (one.get(name) != null) { |
||||
name = resMetaData.getColumnLabel(i); |
||||
} |
||||
if (resultSet.getObject(i) != null && resMetaData.getColumnTypeName(i).equals("DATETIME") || resMetaData.getColumnTypeName(i).equals("TIMESTAMP")) { |
||||
value = resultSet.getObject(i).toString(); |
||||
one.put(name, value.substring(0, value.length() - 2)); |
||||
} else { |
||||
one.put(name, resultSet.getString(i)); |
||||
} |
||||
} |
||||
arrs.add(one); |
||||
} |
||||
pstmt.close(); |
||||
connection.close(); |
||||
return arrs; |
||||
} |
||||
} |
@ -0,0 +1,108 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.config.*; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
|
||||
@Visualization(category = "单点配置") |
||||
public class FLConfig extends DefaultConfiguration { |
||||
|
||||
private static volatile FLConfig config = null; |
||||
@Identifier(value = "valAddr", name = "接口地址", description = "接口地址", status = Status.SHOW) |
||||
private Conf<String> valAddr = Holders.simple(""); |
||||
|
||||
@Identifier(value = "loginClientSecret", name = "secret", description = "Secret", status = Status.SHOW) |
||||
private Conf<String> loginClientSecret = Holders.simple(""); |
||||
@Identifier(value = "threeDdKey", name = "3dsKey", description = "3dsKey", status = Status.SHOW) |
||||
private Conf<String> threeDdKey = Holders.simple("xxx"); |
||||
@Identifier(value = "frUrl", name = "当前fr系统地址", description = "", status = Status.SHOW) |
||||
private Conf<String> frUrl = Holders.simple("http://localhost:8075/webroot/decision"); |
||||
|
||||
@Identifier(value = "method", name = "单点请求方式", description = "单点请求方式", status = Status.SHOW) |
||||
private Conf<String> method = Holders.simple(""); |
||||
|
||||
public static FLConfig getInstance() { |
||||
if (config == null) { |
||||
config = ConfigContext.getConfigInstance(FLConfig.class); |
||||
} |
||||
return config; |
||||
} |
||||
/* |
||||
public String getService() { |
||||
return service.get(); |
||||
} |
||||
|
||||
public void setService(String service) { |
||||
this.service.set(service); |
||||
}*/ |
||||
|
||||
public String getFrUrl() { |
||||
return frUrl.get(); |
||||
} |
||||
|
||||
public void setFrUrl(String frUrl) { |
||||
this.frUrl.set(frUrl); |
||||
} |
||||
|
||||
public String getLoginClientSecret() { |
||||
return loginClientSecret.get(); |
||||
} |
||||
|
||||
public String getThreeDdKey() { |
||||
return threeDdKey.get(); |
||||
} |
||||
|
||||
public void setThreeDdKey(String threeDdKey) { |
||||
this.threeDdKey.set(threeDdKey); |
||||
} |
||||
|
||||
public String getMethod() { |
||||
return method.get(); |
||||
} |
||||
|
||||
public void setMethod(String method) { |
||||
this.method.set(method); |
||||
} |
||||
|
||||
public void setLoginClientSecret(String loginClientSecret) { |
||||
this.loginClientSecret.set(loginClientSecret); |
||||
} |
||||
|
||||
/* public String getAppid() { |
||||
return appid.get(); |
||||
} |
||||
|
||||
public void setAppid(String appid) { |
||||
this.appid.set(appid); |
||||
}*/ |
||||
|
||||
public String getValAddr() { |
||||
return valAddr.get(); |
||||
} |
||||
|
||||
public void setValAddr(String valAddr) { |
||||
this.valAddr.set(valAddr); |
||||
} |
||||
|
||||
/* public String getSysCode() { |
||||
return syscode.get(); |
||||
} |
||||
|
||||
public void setSyscode(String syscode) { |
||||
this.syscode.set(syscode); |
||||
}*/ |
||||
|
||||
|
||||
@Override |
||||
public Object clone() throws CloneNotSupportedException { |
||||
FLConfig cloned = (FLConfig) super.clone(); |
||||
cloned.valAddr = (Conf<String>) valAddr.clone(); |
||||
// cloned.service = (Conf<String>) service.clone();
|
||||
// cloned.appid = (Conf<String>) appid.clone();
|
||||
cloned.loginClientSecret = (Conf<String>) loginClientSecret.clone(); |
||||
cloned.frUrl = (Conf<String>) frUrl.clone(); |
||||
// cloned.syscode = (Conf<String>) syscode.clone();
|
||||
return cloned; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.decision.fun.HttpHandler; |
||||
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; |
||||
import com.fr.plugin.handler.FLLoginCallBackHander; |
||||
|
||||
public class FLHttpHander extends AbstractHttpHandlerProvider { |
||||
|
||||
private HttpHandler[] actions = new HttpHandler[]{new FLLoginCallBackHander()}; |
||||
|
||||
@Override |
||||
public HttpHandler[] registerHandlers() { |
||||
return actions; |
||||
} |
||||
} |
@ -0,0 +1,16 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.plugin.context.PluginContext; |
||||
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; |
||||
|
||||
public class FLLifeCycleMonitor extends AbstractPluginLifecycleMonitor { |
||||
@Override |
||||
public void afterRun(PluginContext pluginContext) { |
||||
FLConfig.getInstance(); |
||||
} |
||||
|
||||
@Override |
||||
public void beforeStop(PluginContext pluginContext) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.decision.authorize.Passport; |
||||
import com.fr.decision.fun.impl.AbstractPassportProvider; |
||||
import com.fr.decision.webservice.bean.authentication.PassportBean; |
||||
|
||||
public class FLPassportProvider extends AbstractPassportProvider { |
||||
public static final String PASSPORT_TYPE = "oauth2"; |
||||
|
||||
@Override |
||||
public String passportType() { |
||||
return PASSPORT_TYPE; |
||||
} |
||||
|
||||
@Override |
||||
public Class<? extends PassportBean> classForPassportBean() { |
||||
return Oauth2Bean.class; |
||||
} |
||||
|
||||
@Override |
||||
public Class<? extends Passport> classForPassportConfig() { |
||||
return Oauth2Passport.class; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractURLAliasProvider; |
||||
import com.fr.decision.webservice.url.alias.URLAlias; |
||||
import com.fr.decision.webservice.url.alias.URLAliasFactory; |
||||
import com.fr.plugin.transform.ExecuteFunctionRecord; |
||||
import com.fr.plugin.transform.FunctionRecorder; |
||||
|
||||
/** |
||||
* 将长连接转换为短连接 |
||||
* 参考文档: |
||||
* https://wiki.fanruan.com/display/PD/com.fr.decision.fun.URLAliasProvider
|
||||
*/ |
||||
@FunctionRecorder |
||||
public class FLURLAliasBridge extends AbstractURLAliasProvider |
||||
{ |
||||
|
||||
@Override |
||||
@ExecuteFunctionRecord |
||||
public URLAlias[] registerAlias() { |
||||
//像这样配置之后再访问/api就可以通过http(s)://ip:port/webroot/decision/url/api。 进行访问
|
||||
return new URLAlias[]{ |
||||
URLAliasFactory.createPluginAlias("/oauth2/login", "/login", true), |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractWebResourceProvider; |
||||
import com.fr.decision.web.MainComponent; |
||||
import com.fr.plugin.transform.ExecuteFunctionRecord; |
||||
import com.fr.plugin.transform.FunctionRecorder; |
||||
import com.fr.stable.fun.Authorize; |
||||
import com.fr.web.struct.Atom; |
||||
@Authorize(callSignKey = "com.fr.plugin.custom.logo" ) |
||||
@FunctionRecorder |
||||
public class LogindJSHandler extends AbstractWebResourceProvider { |
||||
|
||||
/** |
||||
* 需要附加到的主组件 |
||||
* |
||||
* @return 主组件 |
||||
*/ |
||||
|
||||
@Override |
||||
@ExecuteFunctionRecord |
||||
public Atom attach() { |
||||
return MainComponent.KEY; |
||||
} |
||||
|
||||
/** |
||||
* 客户端所需的组件 |
||||
* |
||||
* @return 组件 |
||||
*/ |
||||
@Override |
||||
public Atom client() { |
||||
return LoginedLogoComponent.KEY; |
||||
} |
||||
} |
@ -0,0 +1,54 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fr.plugin.transform.ExecuteFunctionRecord; |
||||
import com.fr.plugin.transform.FunctionRecorder; |
||||
import com.fr.web.struct.Component; |
||||
import com.fr.web.struct.Filter; |
||||
import com.fr.web.struct.browser.RequestClient; |
||||
import com.fr.web.struct.category.ScriptPath; |
||||
import com.fr.web.struct.category.StylePath; |
||||
@FunctionRecorder() |
||||
public class LoginedLogoComponent extends Component { |
||||
public static final LoginedLogoComponent KEY = new LoginedLogoComponent(); |
||||
/** |
||||
* 返回需要引入的JS脚本路径 |
||||
* @param client 请求客户端描述 |
||||
* @return JS脚本路径 |
||||
*/ |
||||
@ExecuteFunctionRecord |
||||
public ScriptPath script( RequestClient client ) { |
||||
PluginLicense pluginLicense = PluginLicenseManager.getInstance().getPluginLicenseByID("com.fr.plugin.custom.logo"); |
||||
if (pluginLicense.isAvailable()) { |
||||
// 做认证通过的事情
|
||||
return ScriptPath.build("com/fr/plugin/web/logined.js"); |
||||
} else { |
||||
// 做认证未通过的事情
|
||||
return ScriptPath.build("com/fr/plugin/web/webnuy.js"); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 返回需要引入的CSS样式路径 |
||||
* @param client 请求客户端描述 |
||||
* @return CSS样式路径 |
||||
*/ |
||||
public StylePath style( RequestClient client ) { |
||||
//如果不需要就直接返回 StylePath.EMPTY;
|
||||
return StylePath.EMPTY; |
||||
} |
||||
|
||||
/** |
||||
* 通过给定的资源过滤器控制是否加载这个资源 |
||||
* @return 资源过滤器 |
||||
*/ |
||||
public Filter filter() { |
||||
return new Filter(){ |
||||
@Override |
||||
public boolean accept() { |
||||
//任何情况下我们都在平台组件加载时加载我们的组件
|
||||
return true; |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fanruan.api.decision.auth.bean.BasePassportBean; |
||||
import com.fr.decision.authorize.Passport; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonSubTypes; |
||||
|
||||
@JsonSubTypes.Type(value = Oauth2Bean.class, name = "LdapAuthenticBean") |
||||
public class Oauth2Bean extends BasePassportBean<Oauth2Passport>{ |
||||
|
||||
@Override |
||||
public String markType() { |
||||
return FLPassportProvider.PASSPORT_TYPE; |
||||
} |
||||
|
||||
@Override |
||||
public BasePassportBean<Oauth2Passport> createPassportBean(Oauth2Passport oauth2Passport) { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public Passport createPassport() { |
||||
Oauth2Passport oauth2Passport = new Oauth2Passport(); |
||||
return oauth2Passport; |
||||
} |
||||
} |
@ -0,0 +1,64 @@
|
||||
package com.fr.plugin; |
||||
|
||||
import com.fanruan.api.conf.HolderKit; |
||||
import com.fanruan.api.decision.auth.BasePassport; |
||||
import com.fanruan.api.net.http.HttpKit; |
||||
import com.fanruan.api.util.AssistKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.config.Identifier; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class Oauth2Passport extends BasePassport { |
||||
@Override |
||||
public String markType() { |
||||
return FLPassportProvider.PASSPORT_TYPE; |
||||
} |
||||
|
||||
@Identifier("emptytoken") |
||||
private Conf<String> emptytoken = HolderKit.simple(StringKit.EMPTY); |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return AssistKit.hashCode(emptytoken.get()); |
||||
} |
||||
|
||||
@Override |
||||
public Object clone() throws CloneNotSupportedException { |
||||
return super.clone(); |
||||
} |
||||
|
||||
public String getEmptytoken() { |
||||
return emptytoken.get(); |
||||
} |
||||
|
||||
public void setEmptytoken(String emptytoken) { |
||||
this.emptytoken.set(emptytoken); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (!(obj instanceof Oauth2Passport)) { |
||||
return false; |
||||
} |
||||
Oauth2Passport target = (Oauth2Passport) obj; |
||||
return AssistKit.equals(target.getEmptytoken(), this.getEmptytoken()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkTicket(String username, String inputPassword, String savedPassword, String hashPassword) { |
||||
//调用接口验证账号密码
|
||||
FLConfig flConfig = FLConfig.getInstance(); |
||||
String url = String.format("%s/am/identity/authenticate?username=%s&password=%s&uri=service=initService", flConfig.getValAddr(), username, inputPassword); |
||||
try { |
||||
String resp = HttpKit.get(url); |
||||
return StringUtils.contains(resp,"token.id="); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1 @@
|
||||
package com.fr.plugin;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import com.fr.log.FineLoggerFactory;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.params.KeyParameter;
/**
* 3DES加密
*
* @author xxx
* @date 2017-10-19
*/
public class ThreeDESUtil {
private static final byte[] HEX_DIGITS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70};
private static DESEngine cipher = new DESEngine();
private static byte[] groupingEncrypt(byte[] key, byte[] data) {
int range = 8;
int iRet = data.length % range;
byte[] out;
if (iRet > 0) {
int length = data.length + (range - iRet);
out = new byte[length];
}
else {
out = new byte[data.length];
}
cipher.init(true, new KeyParameter(key));
int i;
for (i = 0; i < data.length / range; i++) {
cipher.processBlock(data, i * range, out, i * range);
}
if (iRet > 0) {
byte[] temp = new byte[range];
System.arraycopy(data, i * range, temp, 0, iRet);
temp[iRet] = -128;
cipher.processBlock(temp, 0, out, i * range);
}
byte[] toasc = new byte[out.length * 2];
int k = 0;
int j = 0;
for (i = 0; i < out.length; i++) {
k = out[i];
toasc[j++] = HEX_DIGITS[k >>> 4 & 0xf];
toasc[j++] = HEX_DIGITS[k & 0xf];
}
return toasc;
}
private static byte[] groupingDecrypt(byte[] key, byte[] data) {
byte[] result = null;
int range = 2;
int group = 8;
int k = 0;
byte[] tobyte = new byte[data.length / range];
for (int i = 0; i < data.length; i += range) {
char ch;
if (data[i] <= 57) {
ch = (char)(data[i] & 0xf);
}
else {
ch = (char)((data[i] & 0xf) + 9);
}
ch <<= '\004';
if (data[i + 1] <= 57) {
ch |= data[i + 1] & 0xf;
}
else {
ch |= (data[i + 1] & 0xf) + 9;
}
tobyte[k] = (byte)ch;
k++;
}
cipher.init(false, new KeyParameter(key));
if (tobyte.length % group == 0) {
byte[] out = new byte[tobyte.length];
for (int i = 0; i < tobyte.length / group; i++) {
cipher.processBlock(tobyte, i * group, out, i * group);
}
int len = padCount(out);
result = new byte[out.length - len];
System.arraycopy(out, 0, result, 0, out.length - len);
return result;
}
else {
return result;
}
}
private static int padCount(byte[] in) {
int count;
for (count = in.length; count > 0; count--) {
if (in[count - 1] != 0) {
break;
}
}
int minNum = -128;
if (in[count - 1] == minNum) {
return (in.length - count) + 1;
}
else {
return in.length - count;
}
}
/**
* 加密
*
* @param code
* @return
*/
public static final String encode(String code, String key) {
if (code == null) {
return null;
}
else {
try {
byte[] cryptogragh = groupingEncrypt(key.getBytes(StandardCharsets.ISO_8859_1), code.getBytes(StandardCharsets.UTF_8.toString()));
return new String(cryptogragh, StandardCharsets.UTF_8.toString());
}
catch (UnsupportedEncodingException e) {
FineLoggerFactory.getLogger().error(e.toString(), e);
return null;
}
}
}
/**
* 解密
*
* @param code
* @return
*/
public static final String decode(String code, String key) {
if (code == null) {
return null;
}
else {
try {
byte[] debyte = groupingDecrypt(key.getBytes(StandardCharsets.ISO_8859_1), code.getBytes(StandardCharsets.UTF_8.toString()));
return debyte != null ? new String(debyte, StandardCharsets.UTF_8.toString()) : null;
}
catch (UnsupportedEncodingException e) {
FineLoggerFactory.getLogger().error(e.toString(), e);
return null;
}
}
}
} |
@ -0,0 +1,10 @@
|
||||
package com.fr.plugin.exception; |
||||
|
||||
public class ValidException extends RuntimeException{ |
||||
public ValidException() { |
||||
} |
||||
|
||||
public ValidException(String message) { |
||||
super(message); |
||||
} |
||||
} |
@ -0,0 +1,323 @@
|
||||
package com.fr.plugin.handler; |
||||
|
||||
import com.auth0.jwt.JWT; |
||||
import com.auth0.jwt.JWTVerifier; |
||||
import com.auth0.jwt.algorithms.Algorithm; |
||||
import com.auth0.jwt.impl.PublicClaims; |
||||
import com.auth0.jwt.interfaces.Claim; |
||||
import com.auth0.jwt.interfaces.DecodedJWT; |
||||
import com.fanruan.api.net.http.HttpKit; |
||||
import com.fanruan.api.net.http.rs.HttpRequest; |
||||
import com.fanruan.api.net.http.rs.TextResponseHandle; |
||||
import com.finebi.utils.CollectionUtils; |
||||
import com.fr.data.NetworkHelper; |
||||
import com.fr.decision.authority.data.User; |
||||
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||
import com.fr.decision.mobile.terminal.TerminalHandler; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.decision.webservice.v10.login.TokenResource; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.DBUtils; |
||||
import com.fr.plugin.FLConfig; |
||||
import com.fr.plugin.ThreeDESUtil; |
||||
import com.fr.plugin.exception.ValidException; |
||||
import com.fr.security.JwtUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.web.Device; |
||||
import com.fr.third.jodd.util.URLDecoder; |
||||
import com.fr.third.org.apache.http.entity.ContentType; |
||||
import com.fr.third.org.apache.http.nio.entity.NStringEntity; |
||||
import com.fr.third.springframework.web.bind.annotation.RequestMethod; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import javax.servlet.http.HttpSession; |
||||
import java.io.IOException; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
public class FLLoginCallBackHander extends BaseHttpHandler { |
||||
DBUtils dbUtils = new DBUtils("secret-key"); |
||||
|
||||
public static Map<String, Claim> verifyToken(String token, String unifySecred, String key) throws Exception { |
||||
String decode = ThreeDESUtil.decode(unifySecred, key); |
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(decode)).build(); |
||||
Map<String, Claim> mapValue = null; |
||||
if (verifier != null) { |
||||
DecodedJWT jwt = verifier.verify(token); |
||||
if (jwt != null) { |
||||
mapValue = jwt.getClaims(); |
||||
} |
||||
} |
||||
return mapValue; |
||||
} |
||||
|
||||
@Override |
||||
public RequestMethod getMethod() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public String getPath() { |
||||
return "/login"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isPublic() { |
||||
return true; |
||||
} |
||||
|
||||
private String findSecretKey() { |
||||
String sql = "select APP_SECRET from sm2_uuid_secret ORDER BY UPDATE_TIME DESC"; |
||||
try { |
||||
List<Map<String, String>> result = dbUtils.exQuery(sql); |
||||
if (CollectionUtils.isEmpty(result)) { |
||||
return null; |
||||
} |
||||
String secret = result.get(0).get("APP_SECRET"); |
||||
FineLoggerFactory.getLogger().info("oauth login secret :{}", secret); |
||||
return secret; |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("oauth login exception :{}", e.getMessage(), e); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public void getMethodHandle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
String token = req.getParameter("token"); |
||||
String loginName = req.getParameter("loginName"); |
||||
String serviceId = req.getParameter("serviceId"); |
||||
String redirectUrl = req.getParameter("redirectUrl"); |
||||
FineLoggerFactory.getLogger().info("oauth login[get] token:{},loginName:{},serviceId:{},redirectUrl:{}", token, loginName, serviceId, redirectUrl); |
||||
redirectUrl = URLDecoder.decode(redirectUrl); |
||||
if (StringUtils.isNotBlank(token)) { |
||||
String applySexret = findSecretKey(); |
||||
//1. token有效期验证
|
||||
/* if (StringUtils.isNotEmpty(applySexret)) { |
||||
Map<String, Claim> map; |
||||
try { |
||||
map = verifyToken(token, applySexret); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("token校验失败--------------" + e.toString()); |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
return; |
||||
} |
||||
Date date = map.get(PublicClaims.EXPIRES_AT).asDate(); |
||||
int exp = date.compareTo(new Date()); |
||||
if (exp < 0) { |
||||
WebUtils.printAsString(res, "token过期,请重新跳转登录"); |
||||
return; |
||||
} |
||||
}*/ |
||||
//2. 调用接口获取用户信息
|
||||
String username = validGetTokenGetUsername(serviceId, token, loginName); |
||||
UserService userService = UserService.getInstance(); |
||||
User user = userService.getUserByUserName(username); |
||||
if (user != null) { |
||||
login(req, res, username); |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
// String frUrl = xtlConfig.getFrUrl();
|
||||
sendRedirect(res, redirectUrl); |
||||
return; |
||||
} else { |
||||
WebUtils.printAsString(res, "用户" + username + "在帆软系统中不存在"); |
||||
return; |
||||
} |
||||
} else { |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
// sendRedirect(res, goAuth());
|
||||
} |
||||
} |
||||
|
||||
public void postMethodHandle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
String token = req.getParameter("pwdaToken"); |
||||
String loginName = req.getParameter("acctId"); |
||||
String syscode = req.getParameter("syscode"); |
||||
String redirectUrl = req.getParameter("redirectUrl"); |
||||
FineLoggerFactory.getLogger().info("oauth login[post] pwdaToken:{},acctId:{},syscode:{},redirectUrl:{}", token, loginName, syscode, redirectUrl); |
||||
redirectUrl = URLDecoder.decode(redirectUrl); |
||||
if (StringUtils.isNotBlank(token)) { |
||||
String applySexret = findSecretKey(); |
||||
//1. token有效期验证
|
||||
if (StringUtils.isNotEmpty(applySexret)) { |
||||
Map<String, Claim> map; |
||||
try { |
||||
map = verifyToken(token, applySexret, FLConfig.getInstance().getThreeDdKey()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("token校验失败--------------" + e.toString()); |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
return; |
||||
} |
||||
Date date = map.get(PublicClaims.EXPIRES_AT).asDate(); |
||||
int exp = date.compareTo(new Date()); |
||||
if (exp < 0) { |
||||
WebUtils.printAsString(res, "token过期,请重新跳转登录"); |
||||
return; |
||||
} |
||||
} |
||||
//2. 调用接口获取用户信息
|
||||
String username = validPostTokenGetUsername(syscode, token, loginName); |
||||
UserService userService = UserService.getInstance(); |
||||
User user = userService.getUserByUserName(username); |
||||
if (user != null) { |
||||
login(req, res, username); |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
//String frUrl = redirectUrl;//xtlConfig.getFrUrl();
|
||||
sendRedirect(res, redirectUrl); |
||||
return; |
||||
} else { |
||||
WebUtils.printAsString(res, "用户" + username + "在帆软系统中不存在"); |
||||
return; |
||||
} |
||||
} else { |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
try { |
||||
String method = FLConfig.getInstance().getMethod(); |
||||
if (StringUtils.isEmpty(method)) { |
||||
if ("POST".equals(req.getMethod())) {//post提交方式处理逻辑
|
||||
postMethodHandle(req, res); |
||||
} else { |
||||
getMethodHandle(req, res); |
||||
} |
||||
} else if ("GET".equals(method.toUpperCase())) { |
||||
getMethodHandle(req, res); |
||||
} else if ("POST".equals(method.toUpperCase())) { |
||||
postMethodHandle(req, res); |
||||
} else { |
||||
WebUtils.printAsString(res, "请求方式配置异常"); |
||||
} |
||||
} catch (ValidException e) { |
||||
WebUtils.printAsString(res, e.getMessage()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
WebUtils.printAsString(res, "处理异常"); |
||||
} |
||||
} |
||||
|
||||
private String validGetTokenGetUsername(String service, String token, String userName) throws IOException { |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String valAddr = xtlConfig.getValAddr(); |
||||
String url = String.format("%s/checkBwdaToken", valAddr); |
||||
JSONObject req = new JSONObject(); |
||||
req.put("SERVICEID", service); |
||||
req.put("LOGINNAME", userName); |
||||
req.put("TOKEN", token); |
||||
String reqJson = req.toString(); |
||||
url += "?args=" + ThreeDESUtil.encode(reqJson, xtlConfig.getThreeDdKey()); |
||||
; |
||||
FineLoggerFactory.getLogger().info("验证token请求地址:{}", url); |
||||
String resp = HttpKit.get(url, null); |
||||
|
||||
/** |
||||
* SERVICEID 应用标识,由4A统一分配 |
||||
* RSP 成功标识0成功 非0失败 |
||||
* LOGINACCOUNT 当前登录主帐号。应用侧获取当前主帐号 |
||||
* ERRDESC 错误描述,仅当rsp非0时有效 |
||||
*/ |
||||
FineLoggerFactory.getLogger().info("验证token结果响应:{}", resp); |
||||
JSONObject entries = new JSONObject(resp); |
||||
String data = entries.getString("data"); |
||||
entries = new JSONObject(data); |
||||
if (Objects.equals(0, entries.getNumberOfInteger("RSP"))) { |
||||
FineLoggerFactory.getLogger().info("验证token登录成功,获取用户名:{}", entries.getString("LOGINACCOUNT")); |
||||
return entries.getString("LOGINACCOUNT"); |
||||
} else { |
||||
throw new ValidException("4a校验异常"); |
||||
} |
||||
} |
||||
|
||||
private String validPostTokenGetUsername(String syscode, String token, String userName) throws IOException { |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String valAddr = xtlConfig.getValAddr(); |
||||
String url = String.format("%s/checkProwadaToken", valAddr); |
||||
JSONObject req = new JSONObject(); |
||||
req.put("SYSCODE", syscode); |
||||
req.put("ACCTID", userName); |
||||
req.put("TOKEN", token); |
||||
String reqJson = req.toString(); |
||||
url += "?args=" + ThreeDESUtil.encode(reqJson, xtlConfig.getThreeDdKey()); |
||||
String data = ThreeDESUtil.encode(reqJson, xtlConfig.getThreeDdKey()); |
||||
FineLoggerFactory.getLogger().info("验证token请求地址:{}", url); |
||||
JSONObject reqBody = new JSONObject(); |
||||
reqBody.put("args", data); |
||||
String resp = TextResponseHandle.DEFAULT.parse(HttpKit.execute(HttpRequest.custom() |
||||
.url(url) |
||||
.post(new NStringEntity(reqBody.toString(), ContentType.APPLICATION_JSON)).build())); |
||||
// String resp = HttpKit.post(url, null);
|
||||
/** |
||||
* SYSCODE 应用标识,由4A统一分配 |
||||
* RSP 成功标识0成功 非0失败 |
||||
* ACCTNAME 当前登录主帐号登录名 |
||||
* ORGCODE 当前登录账号身份的组织编码 |
||||
* ERRDESC 错误描述,仅当rsp非0时有效 |
||||
*/ |
||||
FineLoggerFactory.getLogger().info("验证token结果响应:{}", resp); |
||||
JSONObject entries = new JSONObject(resp); |
||||
String respData = entries.getString("data"); |
||||
entries = new JSONObject(respData); |
||||
if (Objects.equals(0, entries.getNumberOfInteger("RSP"))) { |
||||
return entries.getString("USERCODE"); |
||||
} else { |
||||
throw new ValidException("4a校验异常"); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void sendRedirect(HttpServletResponse res, String url) throws Exception { |
||||
// WebUtils.printAsString(res, "ok");
|
||||
if (StringUtils.isEmpty(url)) { |
||||
url = FLConfig.getInstance().getFrUrl(); |
||||
} |
||||
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); |
||||
res.setHeader("Location", url); |
||||
FineLoggerFactory.getLogger().info("登录成功,跳转url:", url); |
||||
|
||||
} |
||||
|
||||
private boolean login(HttpServletRequest req, HttpServletResponse res, String username) { |
||||
try { |
||||
String oldToken = TokenResource.COOKIE.getToken(req); |
||||
if ((oldToken == null) || (!checkTokenValid(req, oldToken, username))) { |
||||
HttpSession session = req.getSession(true); |
||||
String token = LoginService.getInstance().login(req, res, username); |
||||
session.setAttribute("fine_auth_token", token); |
||||
FineLoggerFactory.getLogger().error("fr CookieFilter is over with username is ###" + username); |
||||
return true; |
||||
} else { |
||||
FineLoggerFactory.getLogger().error("no need login: {}", username); |
||||
return true; |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private boolean checkTokenValid(HttpServletRequest req, String token, String currentUserName) { |
||||
try { |
||||
if (!ComparatorUtils.equals(currentUserName, JwtUtils.parseJWT(token).getSubject())) { |
||||
FineLoggerFactory.getLogger().info("username changed:" + currentUserName); |
||||
return false; |
||||
} else { |
||||
Device device = NetworkHelper.getDevice(req); |
||||
LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); |
||||
return true; |
||||
} |
||||
} catch (Exception var5) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,286 @@
|
||||
package com.fr.plugin.handler; |
||||
|
||||
import com.auth0.jwt.JWT; |
||||
import com.auth0.jwt.JWTVerifier; |
||||
import com.auth0.jwt.algorithms.Algorithm; |
||||
import com.auth0.jwt.impl.PublicClaims; |
||||
import com.auth0.jwt.interfaces.Claim; |
||||
import com.auth0.jwt.interfaces.DecodedJWT; |
||||
import com.fanruan.api.net.http.HttpKit; |
||||
import com.finebi.utils.CollectionUtils; |
||||
import com.fr.data.NetworkHelper; |
||||
import com.fr.decision.authority.data.User; |
||||
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||
import com.fr.decision.mobile.terminal.TerminalHandler; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.decision.webservice.v10.login.TokenResource; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.DBUtils; |
||||
import com.fr.plugin.FLConfig; |
||||
import com.fr.plugin.ThreeDESUtil; |
||||
import com.fr.plugin.exception.ValidException; |
||||
import com.fr.security.JwtUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.web.Device; |
||||
import com.fr.third.springframework.web.bind.annotation.RequestMethod; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import javax.servlet.http.HttpSession; |
||||
import java.io.IOException; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
public class FLPostLoginCallBackHander extends BaseHttpHandler { |
||||
DBUtils dbUtils = new DBUtils("secret-key"); |
||||
|
||||
public static Map<String, Claim> verifyToken(String token, String unifySecred) throws Exception { |
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(unifySecred)).build(); |
||||
Map<String, Claim> mapValue = null; |
||||
if (verifier != null) { |
||||
DecodedJWT jwt = verifier.verify(token); |
||||
if (jwt != null) { |
||||
mapValue = jwt.getClaims(); |
||||
} |
||||
} |
||||
return mapValue; |
||||
} |
||||
|
||||
@Override |
||||
public RequestMethod getMethod() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public String getPath() { |
||||
return "/login/post"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isPublic() { |
||||
return true; |
||||
} |
||||
|
||||
private String findSecretKey() { |
||||
String sql = "select APP_SECRET from sm2_uuid_secret ORDER BY UPDATE_TIME DESC"; |
||||
try { |
||||
List<Map<String, String>> result = dbUtils.exQuery(sql); |
||||
if (CollectionUtils.isEmpty(result)) { |
||||
return null; |
||||
} |
||||
String secret = result.get(0).get("APP_SECRET"); |
||||
FineLoggerFactory.getLogger().info("oauth login secret :{}", secret); |
||||
return secret; |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("oauth login exception :{}", e.getMessage(), e); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public void getMethodHandle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
String token = req.getParameter("token"); |
||||
String loginName = req.getParameter("loginName"); |
||||
String serviceId = req.getParameter("serviceId"); |
||||
FineLoggerFactory.getLogger().info("oauth login[get] token:{},loginName:{},serviceId:{}", token, loginName, serviceId); |
||||
if (StringUtils.isNotBlank(token)) { |
||||
String applySexret = findSecretKey(); |
||||
//1. token有效期验证
|
||||
/* if (StringUtils.isNotEmpty(applySexret)) { |
||||
Map<String, Claim> map; |
||||
try { |
||||
map = verifyToken(token, applySexret); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("token校验失败--------------" + e.toString()); |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
return; |
||||
} |
||||
Date date = map.get(PublicClaims.EXPIRES_AT).asDate(); |
||||
int exp = date.compareTo(new Date()); |
||||
if (exp < 0) { |
||||
WebUtils.printAsString(res, "token过期,请重新跳转登录"); |
||||
return; |
||||
} |
||||
}*/ |
||||
//2. 调用接口获取用户信息
|
||||
String username = validGetTokenGetUsername(serviceId, token, loginName); |
||||
UserService userService = UserService.getInstance(); |
||||
User user = userService.getUserByUserName(username); |
||||
if (user != null) { |
||||
login(req, res, username); |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String frUrl = xtlConfig.getFrUrl(); |
||||
sendRedirect(res, frUrl); |
||||
return; |
||||
} else { |
||||
WebUtils.printAsString(res, "用户" + username + "在帆软系统中不存在"); |
||||
return; |
||||
} |
||||
} else { |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
// sendRedirect(res, goAuth());
|
||||
} |
||||
} |
||||
|
||||
public void postMethodHandle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
String token = req.getParameter("pwdaToken"); |
||||
String loginName = req.getParameter("acctId"); |
||||
String syscode = req.getParameter("syscode"); |
||||
FineLoggerFactory.getLogger().info("oauth login[get] pwdaToken:{},acctId:{},syscode:{}", token, loginName, syscode); |
||||
|
||||
if (StringUtils.isNotBlank(token)) { |
||||
String applySexret = findSecretKey(); |
||||
//1. token有效期验证
|
||||
if (StringUtils.isNotEmpty(applySexret)) { |
||||
Map<String, Claim> map; |
||||
try { |
||||
map = verifyToken(token, applySexret); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("token校验失败--------------" + e.toString()); |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
return; |
||||
} |
||||
Date date = map.get(PublicClaims.EXPIRES_AT).asDate(); |
||||
int exp = date.compareTo(new Date()); |
||||
if (exp < 0) { |
||||
WebUtils.printAsString(res, "token过期,请重新跳转登录"); |
||||
return; |
||||
} |
||||
} |
||||
//2. 调用接口获取用户信息
|
||||
String username = validPostTokenGetUsername(syscode, token, loginName); |
||||
UserService userService = UserService.getInstance(); |
||||
User user = userService.getUserByUserName(username); |
||||
if (user != null) { |
||||
login(req, res, username); |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String frUrl = xtlConfig.getFrUrl(); |
||||
sendRedirect(res, frUrl); |
||||
return; |
||||
} else { |
||||
WebUtils.printAsString(res, "用户" + username + "在帆软系统中不存在"); |
||||
return; |
||||
} |
||||
} else { |
||||
WebUtils.printAsString(res, "token校验失败"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
try { |
||||
postMethodHandle(req, res); |
||||
} catch (ValidException e) { |
||||
WebUtils.printAsString(res, e.getMessage()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
WebUtils.printAsString(res, "处理异常"); |
||||
} |
||||
} |
||||
|
||||
private String validGetTokenGetUsername(String service, String token, String userName) throws IOException { |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String valAddr = xtlConfig.getValAddr(); |
||||
String url = String.format("%s/checkBwdaToken", valAddr); |
||||
JSONObject req = new JSONObject(); |
||||
req.put("SERVICEID", service); |
||||
req.put("LOGINNAME", userName); |
||||
req.put("TOKEN", token); |
||||
String reqJson = req.toString(); |
||||
url += "?args=" + ThreeDESUtil.encode(reqJson, xtlConfig.getThreeDdKey()); |
||||
; |
||||
FineLoggerFactory.getLogger().info("验证token请求地址:{}", url); |
||||
String resp = HttpKit.get(url, null); |
||||
|
||||
/** |
||||
* SERVICEID 应用标识,由4A统一分配 |
||||
* RSP 成功标识0成功 非0失败 |
||||
* LOGINACCOUNT 当前登录主帐号。应用侧获取当前主帐号 |
||||
* ERRDESC 错误描述,仅当rsp非0时有效 |
||||
*/ |
||||
FineLoggerFactory.getLogger().info("验证token结果响应:{}", resp); |
||||
JSONObject entries = new JSONObject(resp); |
||||
String data = entries.getString("data"); |
||||
entries = new JSONObject(data); |
||||
if (Objects.equals(0, entries.getNumberOfInteger("RSP"))) { |
||||
FineLoggerFactory.getLogger().info("验证token登录成功,获取用户名:{}", entries.getString("LOGINACCOUNT")); |
||||
return entries.getString("LOGINACCOUNT"); |
||||
} else { |
||||
throw new ValidException("4a校验异常"); |
||||
} |
||||
} |
||||
|
||||
private String validPostTokenGetUsername(String syscode, String token, String userName) throws IOException { |
||||
FLConfig xtlConfig = FLConfig.getInstance(); |
||||
String valAddr = xtlConfig.getValAddr(); |
||||
String url = String.format("%s/checkProwadaToken", valAddr); |
||||
JSONObject req = new JSONObject(); |
||||
req.put("SYSCODE", syscode); |
||||
req.put("ACCTID", userName); |
||||
req.put("TOKEN", token); |
||||
String reqJson = req.toString(); |
||||
url += "?args=" + ThreeDESUtil.encode(reqJson, xtlConfig.getThreeDdKey()); |
||||
String resp = HttpKit.get(url, null); |
||||
/** |
||||
* SYSCODE 应用标识,由4A统一分配 |
||||
* RSP 成功标识0成功 非0失败 |
||||
* ACCTNAME 当前登录主帐号登录名 |
||||
* ORGCODE 当前登录账号身份的组织编码 |
||||
* ERRDESC 错误描述,仅当rsp非0时有效 |
||||
*/ |
||||
FineLoggerFactory.getLogger().info("验证token结果响应:{}", resp); |
||||
JSONObject entries = new JSONObject(resp); |
||||
if (Objects.equals(0, entries.getNumberOfInteger("RSP"))) { |
||||
return entries.getString("USERCODE"); |
||||
} else { |
||||
throw new ValidException("4a校验异常"); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void sendRedirect(HttpServletResponse res, String url) { |
||||
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); |
||||
res.setHeader("Location", url); |
||||
} |
||||
|
||||
private boolean login(HttpServletRequest req, HttpServletResponse res, String username) { |
||||
try { |
||||
String oldToken = TokenResource.COOKIE.getToken(req); |
||||
if ((oldToken == null) || (!checkTokenValid(req, oldToken, username))) { |
||||
HttpSession session = req.getSession(true); |
||||
String token = LoginService.getInstance().login(req, res, username); |
||||
session.setAttribute("fine_auth_token", token); |
||||
FineLoggerFactory.getLogger().error("fr CookieFilter is over with username is ###" + username); |
||||
return true; |
||||
} else { |
||||
FineLoggerFactory.getLogger().error("no need login: {}", username); |
||||
return true; |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private boolean checkTokenValid(HttpServletRequest req, String token, String currentUserName) { |
||||
try { |
||||
if (!ComparatorUtils.equals(currentUserName, JwtUtils.parseJWT(token).getSubject())) { |
||||
FineLoggerFactory.getLogger().info("username changed:" + currentUserName); |
||||
return false; |
||||
} else { |
||||
Device device = NetworkHelper.getDevice(req); |
||||
LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); |
||||
return true; |
||||
} |
||||
} catch (Exception var5) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,32 @@
|
||||
;(function ($) { |
||||
|
||||
BI.config("dec.user.setting.authentications", function (items) { |
||||
items.push({ |
||||
value: "oauth2", |
||||
text: "统一认证", |
||||
"@class": "com.fr.plugin.Oauth2Bean", |
||||
component: { |
||||
type: "dec.plugin.custom_oatuh2" |
||||
} |
||||
}); |
||||
return items; |
||||
}); |
||||
var Ldaps = BI.inherit(BI.Widget, { |
||||
|
||||
props: { |
||||
baseCls: "", |
||||
}, |
||||
render: function () { |
||||
var self = this, o = this.options; |
||||
return { |
||||
type: "bi.vertical", |
||||
bgap: 15, |
||||
items: [] |
||||
} |
||||
}, |
||||
getValue: function () { |
||||
return {}; |
||||
} |
||||
}); |
||||
BI.shortcut("dec.plugin.custom_oatuh2", Ldaps); |
||||
})(jQuery) |
Loading…
Reference in new issue