Compare commits
22 Commits
2.0.0.rc25
...
2.0.0.rc44
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90029faa53 | ||
|
|
ecb5aa1b29 | ||
|
|
1db8ef9d85 | ||
|
|
4bcae2f8d1 | ||
|
|
9bab4cdb25 | ||
|
|
856a9f01dd | ||
|
|
e57cd5e1c8 | ||
|
|
542e23ac1b | ||
|
|
6949f50c7c | ||
|
|
7b43ae3ce1 | ||
|
|
8ca283ca85 | ||
|
|
3728291e73 | ||
|
|
6997dea968 | ||
|
|
7f601c8e60 | ||
|
|
7adc2a7c4b | ||
|
|
f4f082cc86 | ||
|
|
d21d84bc87 | ||
|
|
60f996137f | ||
|
|
11c8d234ff | ||
|
|
125c681669 | ||
|
|
b9347013f0 | ||
|
|
3415f0836f |
22
pom.xml
22
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>springboot-parent</name>
|
||||
<description>杭州铁晟科技有限公司基础依赖</description>
|
||||
@@ -58,61 +58,61 @@
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-database</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-login</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-web</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-message</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-encrypt</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-role</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-poi</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-ademo</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
|
||||
@@ -23,9 +23,9 @@ public class DemoWebConfigurer implements TieshengWebConfigurer, TsLoginConfigur
|
||||
@Override
|
||||
public RequestUserInfo getCurrentUserName(TokenBean tokenBean) {
|
||||
RequestUserInfo info = new RequestUserInfo();
|
||||
if (Objects.equals(tokenBean.getId(), "1")) {
|
||||
return info;
|
||||
}
|
||||
info.setId(tokenBean.getId());
|
||||
info.setName(tokenBean.getExtra());
|
||||
info.setData(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.tiesheng.demo.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.TimeInterval;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.read.listener.ReadListener;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.annotation.role.RoleAuthority;
|
||||
import com.tiesheng.annotation.token.TokenIgnore;
|
||||
import com.tiesheng.database.config.DbBackupConfig;
|
||||
import com.tiesheng.demo.pojos.JsonTest;
|
||||
import com.tiesheng.demo.pojos.PoiBean;
|
||||
import com.tiesheng.demo.pojos.TestFile;
|
||||
import com.tiesheng.platform.config.ding.PlatformDingConfig;
|
||||
@@ -22,16 +24,11 @@ import com.tiesheng.util.pojos.ApiResp;
|
||||
import com.tiesheng.util.pojos.FileUploadPath;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
import com.tiesheng.web.service.CoreLogService;
|
||||
import com.tiesheng.web.util.ProcessImportConsumer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -70,7 +67,16 @@ public class TestController {
|
||||
@RequestMapping("/redirect")
|
||||
@TokenIgnore
|
||||
@RoleAuthority("redirect")
|
||||
public ApiResp<String> redirect(HttpServletResponse response) {
|
||||
public ApiResp<JsonTest> redirect(@RequestBody JsonTest dto, HttpServletResponse response) {
|
||||
|
||||
JsonTest jsonTest = new JsonTest();
|
||||
jsonTest.setNow(DateUtil.date());
|
||||
jsonTest.setNow1(DateUtil.date());
|
||||
|
||||
String jsonString = JSON.toJSONString(jsonTest);
|
||||
LogFactory.get().info(jsonString);
|
||||
|
||||
LogFactory.get().info(JSON.toJSONString(dto));
|
||||
|
||||
// ArrayList<String> strings = CollUtil.newArrayList("11111", "22222");
|
||||
// coreLogService.addProcess("fdfd", strings, new ProcessImportConsumer<String>() {
|
||||
@@ -92,7 +98,7 @@ public class TestController {
|
||||
|
||||
// tsTokenConfig.validToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzYwMDY4NzUsImlkIjoiMSIsImVudmlyb25tZW50VHlwZSI6Im1vYmlsZSIsInNlcnZpY2UiOiJjb250ZXN0LXJlc2VydmUiLCJleHRyYSI6IiJ9.nsfxEFpCNHC7eNCS5DJXdu1VDdnHrTjSfgrozND70Lc", true);
|
||||
// globalConfig.redirect("mobile", "/test", response);
|
||||
return ApiResp.respOK("");
|
||||
return ApiResp.respOK(jsonTest);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,18 +201,4 @@ public class TestController {
|
||||
return ApiResp.respOK("");
|
||||
}
|
||||
|
||||
@RequestMapping("poiTool")
|
||||
@TokenIgnore
|
||||
public ApiResp<String> poiTool() {
|
||||
TimeInterval timeInterval = new TimeInterval();
|
||||
|
||||
FileUploadPath file = FileUploadPath.file("/upload/test.xlsx");
|
||||
|
||||
ExcelUtil.getReader(new File(file.getAbsolutePath())).read();
|
||||
|
||||
System.out.println("timeInterval: " + timeInterval.interval());
|
||||
|
||||
return ApiResp.respOK("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.tiesheng.demo.pojos;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class JsonTest {
|
||||
|
||||
private Date now;
|
||||
@JSONField(format = "yyyy-MM-dd")
|
||||
private Date now1;
|
||||
private String no;
|
||||
private String name;
|
||||
|
||||
private JsonTest child;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Date getNow() {
|
||||
return now;
|
||||
}
|
||||
|
||||
public void setNow(Date now) {
|
||||
this.now = now;
|
||||
}
|
||||
|
||||
public Date getNow1() {
|
||||
return now1;
|
||||
}
|
||||
|
||||
public void setNow1(Date now1) {
|
||||
this.now1 = now1;
|
||||
}
|
||||
|
||||
public String getNo() {
|
||||
return no;
|
||||
}
|
||||
|
||||
public void setNo(String no) {
|
||||
this.no = no;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public JsonTest getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(JsonTest child) {
|
||||
this.child = child;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.tiesheng.demo.pojos;
|
||||
|
||||
import com.tiesheng.annotation.desensitize.Desensitize;
|
||||
import com.tiesheng.poi.pojos.PoiWriteBase;
|
||||
|
||||
|
||||
@@ -8,7 +7,6 @@ public class TestParent implements PoiWriteBase {
|
||||
|
||||
private String id;
|
||||
|
||||
@Desensitize()
|
||||
private String test;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.tiesheng.demo.service;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.message.config.aliyun.AliyunSmsHandler;
|
||||
import com.tiesheng.message.config.aliyun.AliyunTempParam;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -15,16 +14,17 @@ public class DemoSmsHandler implements AliyunSmsHandler {
|
||||
@Override
|
||||
public AliyunTempParam handler(JSONObject obj) {
|
||||
|
||||
String action = obj.getStr("action");
|
||||
String action = obj.getString("action");
|
||||
|
||||
AliyunTempParam param = new AliyunTempParam();
|
||||
param.setSignName("智慧校园");
|
||||
|
||||
if (Objects.equals(action, "sms-visitor-invite")) {
|
||||
param.setTemplateCode("SMS_276125463");
|
||||
param.setTemplateParam(JSONUtil.createObj()
|
||||
.putOpt("date", DateUtil.today())
|
||||
);
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("date", DateUtil.today());
|
||||
param.setTemplateParam(object);
|
||||
}
|
||||
|
||||
return param;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.tiesheng.demo.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.web.pojos.imex.ImportDealDTO;
|
||||
import com.tiesheng.web.service.imex.TsImportHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
public class UserImportHandler implements TsImportHandler<String> {
|
||||
|
||||
@Override
|
||||
public List<String> ready(ImportDealDTO dto, TokenBean token) {
|
||||
return CollUtil.newArrayList("11111");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateUrl() {
|
||||
return "/template/xsxxzx_teacher_leader.xlsx";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAction() {
|
||||
return "user_import";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int batchHandler(List<String> list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFailFile() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,9 @@ spring:
|
||||
url: jdbc:mysql://47.96.30.85:3306/com_tiesheng_web?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&queryTimeout=5400&allowMultiQueries=true&serverTimezone=GMT%2B8
|
||||
username: com_tiesheng_web
|
||||
password: 4Xo$XheGFc
|
||||
# redis:
|
||||
# url: redis://kyF0zUL3011111@47.96.30.85:6234
|
||||
redis:
|
||||
url: redis://kyF0zUL3011111@47.96.30.85:6234
|
||||
database: 1
|
||||
|
||||
platform:
|
||||
ding:
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
package com.tiesheng.demo;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import com.tiesheng.demo.pojos.JsonTest;
|
||||
import com.tiesheng.login.pojos.RequestUserInfo;
|
||||
|
||||
public class MainTest {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
MainTest test = new MainTest();
|
||||
test.testJsonSelf();
|
||||
|
||||
}
|
||||
|
||||
private void testJsonSelf() {
|
||||
RequestUserInfo info = new RequestUserInfo();
|
||||
info.setId("1");
|
||||
info.setName("name");
|
||||
info.setData(info);
|
||||
String jsonStr = JSON.toJSONString(info);
|
||||
LogFactory.get().info(jsonStr);
|
||||
}
|
||||
|
||||
|
||||
private void testJsonPath() {
|
||||
JsonTest jsonTest = new JsonTest();
|
||||
jsonTest.setNo("1111");
|
||||
jsonTest.setName("1111");
|
||||
jsonTest.setNow(DateUtil.date());
|
||||
jsonTest.setChild(jsonTest);
|
||||
|
||||
JSONPath jsonPath = JSONPath.compile("child.no");
|
||||
String eval = jsonPath.eval(jsonTest, String.class);
|
||||
LogFactory.get().info(eval);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.tiesheng.annotation.desensitize;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Desensitize {
|
||||
|
||||
int prefix() default 1;
|
||||
|
||||
int suffix() default 1;
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public @interface RoleAuthority {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String platform() default "web";
|
||||
String platform() default "";
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-database</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-encrypt</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.tiesheng.encrypt.config;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.util.config.EncryptConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -66,7 +66,7 @@ public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
|
||||
DecryptHttpInputMessage(HttpInputMessage inputMessage, EncryptConfig encryptConfig) throws Exception {
|
||||
this.headers = inputMessage.getHeaders();
|
||||
String bodyStr = IoUtil.read(inputMessage.getBody(), CharsetUtil.CHARSET_UTF_8);
|
||||
String encryptData = JSONUtil.parseObj(bodyStr).getStr("encryptData");
|
||||
String encryptData = JSON.parseObject(bodyStr).getString("encryptData");
|
||||
if (!StrUtil.isEmpty(encryptData)) {
|
||||
String decrypt = encryptConfig.decrypt(encryptData);
|
||||
this.body = IoUtil.toStream(decrypt, Charset.defaultCharset());
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.tiesheng.encrypt.config;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.util.CommonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.util.config.EncryptConfig;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -42,7 +42,7 @@ public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<ApiResp> {
|
||||
}
|
||||
|
||||
body.setEncrypt(true);
|
||||
body.setData(encryptConfig.encrypt(CommonUtil.writeJsonString(data)));
|
||||
body.setData(encryptConfig.encrypt(JSON.toJSONString(data)));
|
||||
return body;
|
||||
} catch (Exception var17) {
|
||||
LogFactory.get().info("加密数据异常", var17);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-login</artifactId>
|
||||
|
||||
@@ -105,7 +105,7 @@ public class TokenWebMvcConfigurer implements WebMvcConfigurer {
|
||||
TokenBean tokenBean = tsTokenConfig.validToken(request, true);
|
||||
|
||||
// 验证用户是否存在
|
||||
RequestUserInfo cachedUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean);
|
||||
RequestUserInfo cachedUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean, false);
|
||||
if (cachedUserInfo == null) {
|
||||
throw new ApiException("非法TOKEN,请重新登录");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tiesheng.login.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.tiesheng.login.mapper.CoreLogLoginMapper;
|
||||
import com.tiesheng.login.mapper.CorePlatformUniqueMapper;
|
||||
import com.tiesheng.login.pojos.DoLoginInfo;
|
||||
@@ -11,7 +10,9 @@ import com.tiesheng.login.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import com.tiesheng.util.config.Ip2regionConfig;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
import com.tiesheng.util.service.TsServiceBase;
|
||||
import com.tiesheng.util.service.role.TsAuthorityHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -51,6 +52,10 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
|
||||
TokenBean tokenBean = tsLoginConfigurer.login(platformUnique);
|
||||
if (tokenBean != null) {
|
||||
|
||||
// 清除授权信息
|
||||
TsCacheService.of().remove(StrUtil.format(TsAuthorityHandler.CACHE_HAS_AUTHORITY,
|
||||
tokenBean.getRoleId(), tokenBean.getId()));
|
||||
|
||||
// 添加登录日志
|
||||
addLoginLog(platformUnique, tokenBean);
|
||||
|
||||
@@ -60,6 +65,7 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
|
||||
platformUnique.setUserId(tokenBean.getId());
|
||||
saveOrUpdate(platformUnique);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tokenBean;
|
||||
@@ -96,13 +102,13 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
|
||||
public void addLoginLog(CorePlatformUnique platformUnique, TokenBean tokenBean) {
|
||||
|
||||
HttpServletRequest request = ServletKit.getRequest();
|
||||
String ip = ServletUtil.getClientIP(request);
|
||||
String ip = ServletKit.getClientIP(request);
|
||||
|
||||
CoreLogLogin login = new CoreLogLogin();
|
||||
login.setUserId(tokenBean.getId());
|
||||
login.setPlatform(platformUnique.getPlatform());
|
||||
|
||||
RequestUserInfo requestUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean);
|
||||
RequestUserInfo requestUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean, true);
|
||||
login.setUserName(requestUserInfo.getName());
|
||||
|
||||
login.setIp(ip);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.tiesheng.login.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.tiesheng.login.pojos.RequestUserInfo;
|
||||
import com.tiesheng.login.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import com.tiesheng.util.config.TsTokenConfig;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
@@ -37,7 +37,7 @@ public interface TsLoginConfigurer {
|
||||
* 签名错误的时候
|
||||
*/
|
||||
default void onSignError(HttpServletResponse response) {
|
||||
ServletUtil.write(response, "404", "text");
|
||||
ServletKit.write(response, "404", "text");
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ public interface TsLoginConfigurer {
|
||||
* @param tokenBean
|
||||
* @return
|
||||
*/
|
||||
default RequestUserInfo getCachedUserInfo(TokenBean tokenBean) {
|
||||
default RequestUserInfo getCachedUserInfo(TokenBean tokenBean, boolean force) {
|
||||
String key = StrUtil.format(TsTokenConfig.CACHE_REQUEST_LOGIN_KEY, tokenBean.getId());
|
||||
RequestUserInfo obj = TsCacheService.of().getObj(key, RequestUserInfo.class, -1);
|
||||
if (obj == null) {
|
||||
if (obj == null || force) {
|
||||
obj = getCurrentUserName(tokenBean);
|
||||
}
|
||||
if (obj != null) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-message</artifactId>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.tiesheng.message.config.aliyun;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public interface AliyunSmsHandler {
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.message.service.TsMessageSender;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
@@ -103,10 +103,10 @@ public class AliyunSmsSender implements TsMessageSender {
|
||||
try {
|
||||
respBody = OkHttpUtil.get(ENDPOINT + "?Signature=" + signature + sortQueryStringTmp);
|
||||
} catch (Exception e) {
|
||||
respBody = JSONUtil.createObj()
|
||||
.putOpt("Code", "Error")
|
||||
.putOpt("Message", "消息通道异常")
|
||||
.toString();
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("Code", "Error");
|
||||
object.put("Message", "消息通道异常");
|
||||
respBody = object.toJSONString();
|
||||
}
|
||||
return respBody;
|
||||
}
|
||||
@@ -130,9 +130,9 @@ public class AliyunSmsSender implements TsMessageSender {
|
||||
queryMap.put("TemplateParam", tempParam.getTemplateParam().toString());
|
||||
}
|
||||
|
||||
JSONObject respObj = JSONUtil.parseObj(request("SendSms", queryMap));
|
||||
if (!Objects.equals(respObj.getStr("Code"), "OK")) {
|
||||
return ApiResp.resp130(respObj.getStr("Message"));
|
||||
JSONObject respObj = JSON.parseObject(request("SendSms", queryMap));
|
||||
if (!Objects.equals(respObj.getString("Code"), "OK")) {
|
||||
return ApiResp.resp130(respObj.getString("Message"));
|
||||
}
|
||||
|
||||
return ApiResp.respOK("");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.tiesheng.message.config.aliyun;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public class AliyunTempParam {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tiesheng.message.service;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.tiesheng.message.service;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.message.pojos.UserChannel;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.tiesheng.platform.config.ding;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.tiesheng.platform.config.ding.bean.*;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
@@ -80,7 +80,7 @@ public class PlatformDingConfig {
|
||||
Response response = OkHttpUtil.ofHttpClient().build().newCall(request).execute();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
String rawBody = response.body().string();
|
||||
DingResponse<T> bean = JSONUtil.toBean(rawBody, typeReference, true);
|
||||
DingResponse<T> bean = JSON.parseObject(rawBody, typeReference);
|
||||
bean.setRawBody(rawBody);
|
||||
return bean;
|
||||
} else {
|
||||
@@ -116,8 +116,8 @@ public class PlatformDingConfig {
|
||||
query.put("appkey", dingConfigBean.getAppKey());
|
||||
query.put("appsecret", dingConfigBean.getAppSecret());
|
||||
String response = OkHttpUtil.get("https://oapi.dingtalk.com/gettoken", query);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
accessToken = respJson.getStr("access_token");
|
||||
JSONObject respJson = JSON.parseObject(response);
|
||||
accessToken = respJson.getString("access_token");
|
||||
TsCacheService.of().put(CACHE_ACCESS_TOKEN + dingConfigBean.getAppKey(),
|
||||
accessToken, respJson.getLong("expires_in"));
|
||||
|
||||
@@ -174,8 +174,12 @@ public class PlatformDingConfig {
|
||||
* @see <a href="https://open.dingtalk.com/document/isvapp-server/obtain-the-userid-of-a-user-by-using-the-log-free"></a>
|
||||
*/
|
||||
public DingUserSimple getUserIdByCode(String service, String code) {
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("code", code);
|
||||
|
||||
DingResponse<DingUserSimple> resp = doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo",
|
||||
JSONUtil.createObj().putOpt("code", code), new TypeReference<DingResponse<DingUserSimple>>() {
|
||||
object, new TypeReference<DingResponse<DingUserSimple>>() {
|
||||
});
|
||||
return resp.getResult();
|
||||
}
|
||||
@@ -192,9 +196,13 @@ public class PlatformDingConfig {
|
||||
public DingUserInfo topapiV2UserGet(String service, String ddUserId) {
|
||||
DingConfigBean dingConfigBean = getConfigBean(service);
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("userid", ddUserId);
|
||||
|
||||
DingUserInfo userInfo = doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/get",
|
||||
JSONUtil.createObj().putOpt("userid", ddUserId), new TypeReference<DingResponse<DingUserInfo>>() {
|
||||
object, new TypeReference<DingResponse<DingUserInfo>>() {
|
||||
}).getResult();
|
||||
|
||||
// 设置一下job_number
|
||||
userInfo.setJobNumber(userInfo.getJobNumber());
|
||||
userInfo.setAppId(dingConfigBean.getAppKey());
|
||||
@@ -214,8 +222,11 @@ public class PlatformDingConfig {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("dept_id", deptId);
|
||||
|
||||
return doRequest(service, "https://oapi.dingtalk.com/topapi/v2/department/listsub",
|
||||
JSONUtil.createObj().putOpt("dept_id", deptId), new TypeReference<DingResponse<List<DingDeptVo>>>() {
|
||||
object, new TypeReference<DingResponse<List<DingDeptVo>>>() {
|
||||
}).getResult();
|
||||
}
|
||||
|
||||
@@ -232,9 +243,13 @@ public class PlatformDingConfig {
|
||||
return DingUserListVo.fail();
|
||||
}
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("dept_id", deptId);
|
||||
object.put("cursor", cursor);
|
||||
object.put("size", 100);
|
||||
|
||||
return doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/list",
|
||||
JSONUtil.createObj().putOpt("dept_id", deptId).putOpt("cursor", cursor).putOpt("size", 100),
|
||||
new TypeReference<DingResponse<DingUserListVo>>() {
|
||||
object, new TypeReference<DingResponse<DingUserListVo>>() {
|
||||
}).getResult();
|
||||
}
|
||||
|
||||
@@ -293,24 +308,28 @@ public class PlatformDingConfig {
|
||||
DingConfigBean configBean = getConfigBean(service);
|
||||
|
||||
JSONObject msg = new JSONObject();
|
||||
|
||||
if (StrUtil.isEmpty(actionUrl)) {
|
||||
msg.set("msgtype", "markdown");
|
||||
msg.set("markdown", JSONUtil.createObj()
|
||||
.set("title", title).set("text", markdown)
|
||||
);
|
||||
JSONObject markdownObj = new JSONObject();
|
||||
markdownObj.put("title", title);
|
||||
markdownObj.put("text", markdown);
|
||||
|
||||
msg.put("msgtype", "markdown");
|
||||
msg.put("markdown", markdownObj);
|
||||
} else {
|
||||
msg.set("msgtype", "action_card");
|
||||
msg.set("action_card", JSONUtil.createObj()
|
||||
.set("title", title).set("markdown", markdown)
|
||||
.set("single_title", "点击查看").set("single_url", actionUrl)
|
||||
);
|
||||
JSONObject actionCard = new JSONObject();
|
||||
actionCard.put("title", title);
|
||||
actionCard.put("markdown", markdown);
|
||||
actionCard.put("single_title", "点击查看");
|
||||
actionCard.put("single_url", actionUrl);
|
||||
|
||||
msg.put("msgtype", "action_card");
|
||||
msg.put("action_card", actionCard);
|
||||
}
|
||||
|
||||
JSONObject body = new JSONObject();
|
||||
body.putOpt("agent_id", configBean.getAgentId());
|
||||
body.putOpt("userid_list", CollUtil.join(userIds, ","));
|
||||
body.putOpt("msg", msg);
|
||||
body.put("agent_id", configBean.getAgentId());
|
||||
body.put("userid_list", CollUtil.join(userIds, ","));
|
||||
body.put("msg", msg);
|
||||
return doRequest(service, "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2", body,
|
||||
new TypeReference<DingResponse<String>>() {
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -41,7 +42,8 @@ public class DingResponse<T> {
|
||||
* @return
|
||||
*/
|
||||
public <E> E getRawValue(String path, Class<E> tClass) {
|
||||
return JSONUtil.parse(getRawBody()).getByPath(path, tClass);
|
||||
JSONPath jsonPath = JSONPath.compile(path);
|
||||
return jsonPath.eval(JSON.parseObject(getRawBody()), tClass);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.tiesheng.platform.config.wxmini;
|
||||
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.service.http.OkHttpUtil;
|
||||
@@ -56,8 +56,8 @@ public class PlatformWxminiConfig {
|
||||
+ "&secret=" + configBean.getAppSecret()
|
||||
+ "&js_code=" + code + "&grant_type=authorization_code");
|
||||
|
||||
JSONObject object = JSONUtil.parseObj(body);
|
||||
return object.getStr("openid");
|
||||
JSONObject object = JSON.parseObject(body);
|
||||
return object.getString("openid");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,8 +72,8 @@ public class PlatformWxminiConfig {
|
||||
+ "?grant_type=client_credential&appid=" + configBean.getAppId()
|
||||
+ "&secret=" + configBean.getAppSecret());
|
||||
|
||||
JSONObject object = JSONUtil.parseObj(body);
|
||||
return object.getStr("access_token");
|
||||
JSONObject object = JSON.parseObject(body);
|
||||
return object.getString("access_token");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ package com.tiesheng.platform.config.wxmp;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxOAuth2AccessToken;
|
||||
@@ -70,8 +70,8 @@ public class PlatformWxmpConfig {
|
||||
query.put("appid", configBean.getAppId());
|
||||
query.put("secret", configBean.getAppSecret());
|
||||
String response = OkHttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", query);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
accessToken = respJson.getStr("access_token");
|
||||
JSONObject respJson = JSON.parseObject(response);
|
||||
accessToken = respJson.getString("access_token");
|
||||
TsCacheService.of().put(CACHE_ACCESS_TOKEN + configBean.getAppId(), accessToken,
|
||||
respJson.getLong("expires_in"));
|
||||
}
|
||||
@@ -93,8 +93,8 @@ public class PlatformWxmpConfig {
|
||||
query.put("type", "jsapi");
|
||||
String response = OkHttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", query);
|
||||
LogFactory.get().info("getJsapiTicket: " + response);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
jsapiTicket = respJson.getStr("ticket");
|
||||
JSONObject respJson = JSON.parseObject(response);
|
||||
jsapiTicket = respJson.getString("ticket");
|
||||
TsCacheService.of().put(CACHE_JSAPI_TICKET + configBean.getAppId(), jsapiTicket,
|
||||
respJson.getLong("expires_in"));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.util.service.http.OkHttpUtil;
|
||||
|
||||
/**
|
||||
@@ -15,11 +15,11 @@ public class WxOAuth2AccessToken {
|
||||
public static WxOAuth2AccessToken create(String appId, String secret, String code) {
|
||||
String response = OkHttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token" +
|
||||
"?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
JSONObject respJson = JSON.parseObject(response);
|
||||
|
||||
WxOAuth2AccessToken oAuth2AccessToken = new WxOAuth2AccessToken();
|
||||
oAuth2AccessToken.setOpenid(respJson.getStr("openid"));
|
||||
oAuth2AccessToken.setAccessToken(respJson.getStr("access_token"));
|
||||
oAuth2AccessToken.setOpenid(respJson.getString("openid"));
|
||||
oAuth2AccessToken.setAccessToken(respJson.getString("access_token"));
|
||||
return oAuth2AccessToken;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.util.service.http.OkHttpUtil;
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ public class WxUserInfo {
|
||||
String s = OkHttpUtil.get("https://api.weixin.qq.com/sns/userinfo"
|
||||
+ "?access_token=" + oAuth2AccessToken.getAccessToken()
|
||||
+ "&openid=" + oAuth2AccessToken.getOpenid() + "&lang=zh_CN");
|
||||
return JSONUtil.toBean(s, WxUserInfo.class);
|
||||
return JSON.parseObject(s, WxUserInfo.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-poi</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-role</artifactId>
|
||||
|
||||
@@ -103,6 +103,7 @@ public class RoleGroupController {
|
||||
List<CoreRoleGroupRx> list = coreRoleService.getGroupRxMapper().selectList(new QueryWrapper<CoreRoleGroupRx>()
|
||||
.eq(CoreRoleGroupRx.IS_DELETED, 0)
|
||||
.eq("group_id", dto.getId())
|
||||
.eq("type", "bind")
|
||||
);
|
||||
return ApiResp.respOK(list);
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ public interface CoreRoleGroupRxMapper extends BaseMapper<CoreRoleGroupRx> {
|
||||
* @return
|
||||
*/
|
||||
int batchInsert(@Param("list") List<CoreRoleGroupRx> coreRoleGroupRxs);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public interface CoreRoleUserMapper extends BaseMapper<CoreRoleUser> {
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
List<CoreRoleAuthority> getOwnerAuthorityLeafList(@Param("userId") String userId,
|
||||
@Param("roleId") String roleId);
|
||||
List<CoreRoleAuthority> getOwnerAuthorityLeafList(@Param("userId") String userId, @Param("roleId") String roleId,
|
||||
@Param("type") String type);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.tiesheng.role.pojos.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.tiesheng.util.pojos.DaoBase;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 角色-权限
|
||||
@@ -81,6 +84,18 @@ public class CoreRoleAuthority extends DaoBase {
|
||||
@TableField(value = "version")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 权限来源:auto-自动生成,input-添加
|
||||
*/
|
||||
@TableField(value = "`source`")
|
||||
private String source;
|
||||
|
||||
/**
|
||||
* 依赖权限
|
||||
*/
|
||||
@TableField(value = "deps")
|
||||
private String deps;
|
||||
|
||||
/**
|
||||
* 扩展1
|
||||
*/
|
||||
@@ -315,6 +330,42 @@ public class CoreRoleAuthority extends DaoBase {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限来源:auto-自动生成,input-添加
|
||||
*
|
||||
* @return source - 权限来源:auto-自动生成,input-添加
|
||||
*/
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置权限来源:auto-自动生成,input-添加
|
||||
*
|
||||
* @param source 权限来源:auto-自动生成,input-添加
|
||||
*/
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取依赖权限
|
||||
*
|
||||
* @return deps - 依赖权限
|
||||
*/
|
||||
public String getDeps() {
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置依赖权限
|
||||
*
|
||||
* @param deps 依赖权限
|
||||
*/
|
||||
public void setDeps(String deps) {
|
||||
this.deps = deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展1
|
||||
*
|
||||
@@ -368,4 +419,4 @@ public class CoreRoleAuthority extends DaoBase {
|
||||
public void setExt3(String ext3) {
|
||||
this.ext3 = ext3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,12 @@ public class CoreRoleGroupRx extends DaoBase {
|
||||
@TableField(value = "menu_id")
|
||||
private String menuId;
|
||||
|
||||
/**
|
||||
* 关联类型:dep-依赖,bind-绑定
|
||||
*/
|
||||
@TableField(value = "`type`")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 获取角色id
|
||||
*
|
||||
@@ -59,4 +65,22 @@ public class CoreRoleGroupRx extends DaoBase {
|
||||
public void setMenuId(String menuId) {
|
||||
this.menuId = menuId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联类型:dep-依赖,bind-绑定
|
||||
*
|
||||
* @return type - 关联类型:dep-依赖,bind-绑定
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置关联类型:dep-依赖,bind-绑定
|
||||
*
|
||||
* @param type 关联类型:dep-依赖,bind-绑定
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.tiesheng.role.service;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.tiesheng.annotation.role.RoleAuthority;
|
||||
import com.tiesheng.role.mapper.*;
|
||||
import com.tiesheng.role.pojos.dao.CoreRoleAuthority;
|
||||
import com.tiesheng.role.pojos.dao.CoreRoleGroup;
|
||||
@@ -21,21 +19,15 @@ import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
import com.tiesheng.util.service.TsServiceBase;
|
||||
import com.tiesheng.util.service.role.TsAuthorityHandler;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRoleGroup>
|
||||
implements ApplicationListener<ContextRefreshedEvent> {
|
||||
public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRoleGroup> {
|
||||
|
||||
@Resource
|
||||
CoreRoleUserMapper coreRoleUserMapper;
|
||||
@@ -45,8 +37,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
|
||||
CoreRoleAuthorityMapper coreRoleAuthorityMapper;
|
||||
@Resource
|
||||
CoreRoleServerMapper coreRoleServerMapper;
|
||||
@Resource
|
||||
TsAuthorityHandler tsAuthorityHandler;
|
||||
|
||||
|
||||
public CoreRoleServerMapper getServerMapper() {
|
||||
return coreRoleServerMapper;
|
||||
@@ -130,7 +121,17 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
|
||||
CoreRoleGroupRx coreRoleGroupRx = new CoreRoleGroupRx();
|
||||
coreRoleGroupRx.setGroupId(roleGroup.getId());
|
||||
coreRoleGroupRx.setMenuId(authority.getId());
|
||||
coreRoleGroupRx.setType("bind");
|
||||
list.add(coreRoleGroupRx);
|
||||
|
||||
List<String> deps = JSON.parseArray(authority.getDeps(), String.class);
|
||||
for (String dep : deps) {
|
||||
CoreRoleGroupRx depRx = new CoreRoleGroupRx();
|
||||
depRx.setGroupId(roleGroup.getId());
|
||||
depRx.setMenuId(StrUtil.format("{}_{}", authority.getService(), dep));
|
||||
depRx.setType("dep");
|
||||
list.add(depRx);
|
||||
}
|
||||
}
|
||||
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
@@ -189,7 +190,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
|
||||
* @return
|
||||
*/
|
||||
public List<CoreRoleAuthority> getOwnerAuthorityLeafList(String userId, String roleId) {
|
||||
return coreRoleUserMapper.getOwnerAuthorityLeafList(userId, roleId);
|
||||
return coreRoleUserMapper.getOwnerAuthorityLeafList(userId, roleId, "bind");
|
||||
}
|
||||
|
||||
|
||||
@@ -230,41 +231,11 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
|
||||
|
||||
return menuChildrenWrap(ownerAuthorityList.stream()
|
||||
.filter(it -> Objects.equals(it.getType(), "group") || Objects.equals(it.getType(), "menu"))
|
||||
.filter(it -> Objects.equals(it.getService(), dto.getService()) && Objects.equals(it.getPlatform(), dto.getPlatform()))
|
||||
.collect(Collectors.toList()), null)
|
||||
.stream().sorted(Comparator.comparingInt(ServiceMenuVO::getSort))
|
||||
.map(ServiceMenuVO::sortChildren)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
Map<String, Object> beansOfType = applicationContext.getBeansWithAnnotation(RoleAuthority.class);
|
||||
|
||||
String version = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||
|
||||
for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
|
||||
|
||||
Class<?> targetClass = AopUtils.getTargetClass(entry.getValue());
|
||||
RoleAuthority menu = targetClass.getAnnotation(RoleAuthority.class);
|
||||
|
||||
List<RoleAuthority> points = new ArrayList<>();
|
||||
Method[] methods = targetClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
RoleAuthority methodAuthority = AnnotationUtil.getAnnotation(method, RoleAuthority.class);
|
||||
if (methodAuthority != null) {
|
||||
points.add(methodAuthority);
|
||||
}
|
||||
}
|
||||
|
||||
tsAuthorityHandler.addRoleAuthority(version, menu, points);
|
||||
}
|
||||
|
||||
coreRoleAuthorityMapper.delete(new QueryWrapper<CoreRoleAuthority>()
|
||||
.ne("version", version)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.tiesheng.role.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.tiesheng.annotation.role.RoleAuthority;
|
||||
import com.tiesheng.role.mapper.CoreRoleAuthorityMapper;
|
||||
import com.tiesheng.role.mapper.CoreRoleUserMapper;
|
||||
@@ -32,6 +34,8 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
String menuPlatform = StrUtil.emptyToDefault(menu.platform(), "web");
|
||||
|
||||
List<CoreRoleAuthority> list = new ArrayList<>();
|
||||
|
||||
// 分组
|
||||
@@ -52,9 +56,10 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
|
||||
groupAuthority.setService(globalConfig.getService());
|
||||
groupAuthority.setType("group");
|
||||
groupAuthority.setLevel(level);
|
||||
groupAuthority.setPlatform(menu.platform());
|
||||
groupAuthority.setPlatform(menuPlatform);
|
||||
groupAuthority.setParent(parentId);
|
||||
groupAuthority.setVersion(version);
|
||||
groupAuthority.setSource("auto");
|
||||
groupAuthority.setId(StrUtil.join("_", groupAuthority.getService(), groupAuthority.getNo()));
|
||||
list.add(groupAuthority);
|
||||
}
|
||||
@@ -68,8 +73,10 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
|
||||
menuAuthority.setType("menu");
|
||||
menuAuthority.setLevel(groupAuthority.getLevel() + 1);
|
||||
menuAuthority.setParent(groupAuthority.getId());
|
||||
menuAuthority.setPlatform(menu.platform());
|
||||
menuAuthority.setPlatform(menuPlatform);
|
||||
menuAuthority.setVersion(version);
|
||||
menuAuthority.setSource("auto");
|
||||
menuAuthority.setDeps(JSON.toJSONString(menu.deps()));
|
||||
menuAuthority.setId(StrUtil.join("_", menuAuthority.getService(), menuAuthority.getNo()));
|
||||
list.add(menuAuthority);
|
||||
|
||||
@@ -83,7 +90,9 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
|
||||
point.setLevel(menuAuthority.getLevel() + 1);
|
||||
point.setParent(menuAuthority.getId());
|
||||
point.setVersion(version);
|
||||
point.setPlatform(StrUtil.emptyToDefault(authority.platform(), menu.platform()));
|
||||
point.setSource("auto");
|
||||
point.setDeps(JSON.toJSONString(authority.deps()));
|
||||
point.setPlatform(StrUtil.emptyToDefault(authority.platform(), menuPlatform));
|
||||
point.setId(StrUtil.join("_", point.getService(), point.getNo()));
|
||||
list.add(point);
|
||||
}
|
||||
@@ -95,8 +104,17 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
|
||||
@Override
|
||||
public List<String> getAuthorities(TokenBean tokenBean) {
|
||||
List<CoreRoleAuthority> list = coreRoleUserMapper.getOwnerAuthorityLeafList(tokenBean.getId(),
|
||||
tokenBean.getRoleId());
|
||||
tokenBean.getRoleId(), "");
|
||||
return list.stream().map(CoreRoleAuthority::getNo).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateAfter(String version) {
|
||||
coreRoleAuthorityMapper.delete(new QueryWrapper<CoreRoleAuthority>()
|
||||
.ne("version", version)
|
||||
.eq("service", globalConfig.getService())
|
||||
.eq("source", "auto")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -99,4 +99,13 @@ create table core_role_user
|
||||
alter table core_role_authority
|
||||
add version varchar(50) null comment '版本号' after platform;
|
||||
|
||||
alter table core_role_authority
|
||||
add source varchar(10) null comment '权限来源:auto-自动生成,input-添加' after version;
|
||||
|
||||
alter table core_role_authority
|
||||
add deps text null comment '依赖权限' after source;
|
||||
|
||||
alter table core_role_group_rx
|
||||
add type varchar(10) null comment '关联类型:dep-依赖,bind-绑定';
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<result column="link" jdbcType="LONGVARCHAR" property="link" />
|
||||
<result column="platform" jdbcType="VARCHAR" property="platform" />
|
||||
<result column="version" jdbcType="VARCHAR" property="version" />
|
||||
<result column="source" jdbcType="VARCHAR" property="source" />
|
||||
<result column="deps" jdbcType="LONGVARCHAR" property="deps" />
|
||||
<result column="ext1" jdbcType="VARCHAR" property="ext1" />
|
||||
<result column="ext2" jdbcType="VARCHAR" property="ext2" />
|
||||
<result column="ext3" jdbcType="VARCHAR" property="ext3" />
|
||||
@@ -27,12 +29,12 @@
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, create_time, update_time, is_deleted, service, `no`, `name`, sort, `level`, parent,
|
||||
remark, is_open, `type`, link, platform, version, ext1, ext2, ext3
|
||||
remark, is_open, `type`, link, platform, version, `source`, deps, ext1, ext2, ext3
|
||||
</sql>
|
||||
|
||||
<insert id="batchInsert">
|
||||
insert into core_role_authority(id, create_time, update_time, is_deleted, service, no, name, level, parent,
|
||||
type, platform, is_open, version)
|
||||
type, platform, is_open, version, source, deps)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id}, now(), now(), 0,
|
||||
@@ -42,7 +44,7 @@
|
||||
#{item.level},
|
||||
#{item.parent},
|
||||
#{item.type},
|
||||
#{item.platform}, 1, #{item.version})
|
||||
#{item.platform}, 1, #{item.version}, #{item.source}, #{item.deps})
|
||||
</foreach>
|
||||
|
||||
on duplicate key update update_time=now(),
|
||||
@@ -51,6 +53,8 @@
|
||||
parent=values(parent),
|
||||
type=values(type),
|
||||
platform=values(platform),
|
||||
source=values(source),
|
||||
deps=values(deps),
|
||||
version=values(version)
|
||||
</insert>
|
||||
|
||||
|
||||
@@ -10,19 +10,20 @@
|
||||
<result column="is_deleted" jdbcType="INTEGER" property="isDeleted" />
|
||||
<result column="group_id" jdbcType="VARCHAR" property="groupId" />
|
||||
<result column="menu_id" jdbcType="VARCHAR" property="menuId" />
|
||||
<result column="type" jdbcType="VARCHAR" property="type" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, create_time, update_time, is_deleted, group_id, menu_id
|
||||
id, create_time, update_time, is_deleted, group_id, menu_id, `type`
|
||||
</sql>
|
||||
|
||||
<insert id="batchInsert">
|
||||
insert into core_role_group_rx(id, create_time, update_time, is_deleted, group_id, menu_id)
|
||||
insert into core_role_group_rx(id, create_time, update_time, is_deleted, group_id, menu_id,type)
|
||||
values
|
||||
<foreach collection="list" separator="," item="item">
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(uuid(), now(), now(), 0,
|
||||
#{item.groupId},
|
||||
#{item.menuId})
|
||||
#{item.menuId}, #{item.type})
|
||||
</foreach>
|
||||
</insert>
|
||||
</mapper>
|
||||
|
||||
@@ -50,10 +50,13 @@
|
||||
select crgr.menu_id
|
||||
from core_role_user cru
|
||||
left join core_role_group_rx crgr on crgr.group_id = cru.type_id
|
||||
where type = 'job'
|
||||
and user_id = #{userId}
|
||||
where cru.type = 'job'
|
||||
and cru.user_id = #{userId}
|
||||
and cru.is_deleted = 0
|
||||
and (cru.expire_time is null or cru.expire_time > now())
|
||||
<if test="type != null and type != ''">
|
||||
and crgr.type=#{type}
|
||||
</if>
|
||||
|
||||
<if test="roleId != null and roleId != ''">
|
||||
union
|
||||
@@ -61,6 +64,9 @@
|
||||
select menu_id
|
||||
from core_role_group_rx
|
||||
where group_id = #{roleId}
|
||||
<if test="type != null and type != ''">
|
||||
and type=#{type}
|
||||
</if>
|
||||
</if>
|
||||
)
|
||||
order by sort
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-util</artifactId>
|
||||
@@ -15,6 +15,7 @@
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<hutool.version>5.8.31</hutool.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -32,15 +33,44 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
<version>5.8.16</version>
|
||||
<type>pom</type>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-cache</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-log</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-db</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -4,10 +4,8 @@ package com.tiesheng.util;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public class CharacterUtils {
|
||||
|
||||
@@ -24,19 +22,24 @@ public class CharacterUtils {
|
||||
/**
|
||||
* 移除特殊字符
|
||||
*
|
||||
* @param o 类
|
||||
* @param o 类
|
||||
* @param searchStr 规则
|
||||
*/
|
||||
public static void removeSymbol(Object o, String searchStr) {
|
||||
JSONObject object = JSONUtil.parseObj(o, false);
|
||||
for (Map.Entry<String, Object> entry : object) {
|
||||
if (ObjectUtil.isEmpty(entry.getValue()) || StrUtil.equals("null", String.valueOf(entry.getValue()))) {
|
||||
entry.setValue("");
|
||||
JSONObject object = JSON.parseObject(JSON.toJSONString(o));
|
||||
for (String key : object.keySet()) {
|
||||
if (StrUtil.isEmpty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(entry.getKey())) {
|
||||
entry.setValue(StrUtil.trim(StrUtil.replace(entry.getValue().toString(), searchStr, "")));
|
||||
|
||||
Object value = object.get(key);
|
||||
if (ObjectUtil.isEmpty(value) || StrUtil.equals("null", String.valueOf(value))) {
|
||||
object.put(key, "");
|
||||
continue;
|
||||
}
|
||||
|
||||
String replace = StrUtil.replace(String.valueOf(value), searchStr, "");
|
||||
object.put(key, StrUtil.trim(replace));
|
||||
}
|
||||
BeanUtil.copyProperties(object, o);
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.tiesheng.util;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.tiesheng.util.config.DesensitizeValueFilter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CommonUtil {
|
||||
|
||||
|
||||
/**
|
||||
* FastJson配置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static FastJsonConfig fastJsonConfig() {
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,
|
||||
SerializerFeature.WriteNullStringAsEmpty,
|
||||
SerializerFeature.WriteEnumUsingName,
|
||||
SerializerFeature.DisableCircularReferenceDetect
|
||||
);
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializeFilters(new DesensitizeValueFilter());
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 格式化数据
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String writeJsonString(Object value) throws IOException {
|
||||
FastJsonConfig fastJsonConfig = fastJsonConfig();
|
||||
ByteArrayOutputStream outnew = new ByteArrayOutputStream();
|
||||
JSON.writeJSONStringWithFastJsonConfig(outnew, fastJsonConfig.getCharset(),
|
||||
value, fastJsonConfig.getSerializeConfig(),
|
||||
fastJsonConfig.getSerializeFilters(),
|
||||
fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE,
|
||||
fastJsonConfig.getSerializerFeatures());
|
||||
return outnew.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.tiesheng.util.config;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.serializer.ValueFilter;
|
||||
import com.tiesheng.annotation.desensitize.Desensitize;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 脱敏过滤类
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
public class DesensitizeValueFilter implements ValueFilter {
|
||||
|
||||
@Override
|
||||
public Object process(Object object, String name, Object value) {
|
||||
if (ObjectUtil.isEmpty(value) || !(value instanceof String)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Field field = ReflectUtil.getField(object.getClass(), name);
|
||||
if (ObjectUtil.isEmpty(field)) {
|
||||
return value;
|
||||
}
|
||||
Desensitize desensitize = field.getAnnotation(Desensitize.class);
|
||||
if (String.class != field.getType() || ObjectUtil.isEmpty(desensitize)) {
|
||||
return value;
|
||||
}
|
||||
String originVal = String.valueOf(value);
|
||||
return StrUtil.hide(originVal, desensitize.prefix(),
|
||||
StrUtil.length(originVal) - desensitize.suffix());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -26,6 +28,18 @@ import java.util.List;
|
||||
@ConfigurationProperties(prefix = "tiesheng.global")
|
||||
public class GlobalConfig {
|
||||
|
||||
static {
|
||||
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
// FASTJSON 设置全局序列化配置
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteMapNullValue.getMask();
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNullStringAsEmpty.getMask();
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteEnumUsingName.getMask();
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteDateUseDateFormat.getMask();
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
|
||||
}
|
||||
|
||||
|
||||
private String host;
|
||||
private String service;
|
||||
private String version;
|
||||
|
||||
@@ -4,10 +4,10 @@ package com.tiesheng.util.config;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTValidator;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.jwt.JWT;
|
||||
import com.tiesheng.util.jwt.JWTValidator;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -81,7 +81,7 @@ public class TsTokenConfig {
|
||||
try {
|
||||
JWT decode = JWT.of(token);
|
||||
JWTValidator.of(decode).validateDate();
|
||||
tokenBean = JSONUtil.toBean(decode.getPayloads(), TokenBean.class);
|
||||
tokenBean = JSON.toJavaObject(decode.getPayloads(), TokenBean.class);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Claims 认证,简单的JSONObject包装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class Claims implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JSONObject claimJSON;
|
||||
|
||||
/**
|
||||
* 增加Claims属性,如果属性值为{@code null},则移除这个属性
|
||||
*
|
||||
* @param name 属性名
|
||||
* @param value 属性值
|
||||
*/
|
||||
protected void setClaim(String name, Object value) {
|
||||
init();
|
||||
Assert.notNull(name, "Name must be not null!");
|
||||
if (value == null) {
|
||||
claimJSON.remove(name);
|
||||
return;
|
||||
}
|
||||
claimJSON.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入多个Claims属性
|
||||
*
|
||||
* @param headerClaims 多个Claims属性
|
||||
*/
|
||||
protected void putAll(Map<String, ?> headerClaims) {
|
||||
if (MapUtil.isNotEmpty(headerClaims)) {
|
||||
for (Map.Entry<String, ?> entry : headerClaims.entrySet()) {
|
||||
setClaim(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称属性
|
||||
*
|
||||
* @param name 名称
|
||||
* @return 属性
|
||||
*/
|
||||
public Object getClaim(String name) {
|
||||
init();
|
||||
return this.claimJSON.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Claims的JSON字符串形式
|
||||
*
|
||||
* @return JSON字符串
|
||||
*/
|
||||
public JSONObject getClaimsJson() {
|
||||
init();
|
||||
return this.claimJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT JSON
|
||||
*
|
||||
* @param tokenPart JWT JSON
|
||||
* @param charset 编码
|
||||
*/
|
||||
public void parse(String tokenPart, Charset charset) {
|
||||
this.claimJSON = JSON.parseObject(Base64.decodeStr(tokenPart, charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
init();
|
||||
return this.claimJSON.toString();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (null == this.claimJSON) {
|
||||
this.claimJSON = new JSONObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
433
springboot-util/src/main/java/com/tiesheng/util/jwt/JWT.java
Normal file
433
springboot-util/src/main/java/com/tiesheng/util/jwt/JWT.java
Normal file
@@ -0,0 +1,433 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.exceptions.ValidateException;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.util.jwt.signers.AlgorithmUtil;
|
||||
import com.tiesheng.util.jwt.signers.JWTSigner;
|
||||
import com.tiesheng.util.jwt.signers.JWTSignerUtil;
|
||||
import com.tiesheng.util.jwt.signers.NoneJWTSigner;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JSON Web Token (JWT),基于JSON的开放标准((RFC 7519)用于在网络应用环境间传递声明。<br>
|
||||
* <p>
|
||||
* 结构:header.payload.signature
|
||||
* <ul>
|
||||
* <li>header:主要声明了JWT的签名算法</li>
|
||||
* <li>payload:主要承载了各种声明并传递明文数据</li>
|
||||
* <li>signature:拥有该部分的JWT被称为JWS,也就是签了名的JWS</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* 详细介绍见;https://www.jianshu.com/p/576dbf44b2ae
|
||||
* </p>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class JWT implements RegisteredPayload<JWT> {
|
||||
|
||||
private final JWTHeader header;
|
||||
private final JWTPayload payload;
|
||||
|
||||
private Charset charset;
|
||||
private JWTSigner signer;
|
||||
|
||||
private List<String> tokens;
|
||||
|
||||
/**
|
||||
* 创建空的JWT对象
|
||||
*
|
||||
* @return JWT
|
||||
*/
|
||||
public static JWT create() {
|
||||
return new JWT();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并解析JWT对象
|
||||
*
|
||||
* @param token JWT Token字符串,格式为xxxx.yyyy.zzzz
|
||||
* @return JWT
|
||||
*/
|
||||
public static JWT of(String token) {
|
||||
return new JWT(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public JWT() {
|
||||
this.header = new JWTHeader();
|
||||
this.payload = new JWTPayload();
|
||||
this.charset = CharsetUtil.CHARSET_UTF_8;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param token JWT Token字符串,格式为xxxx.yyyy.zzzz
|
||||
*/
|
||||
public JWT(String token) {
|
||||
this();
|
||||
parse(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT内容
|
||||
*
|
||||
* @param token JWT Token字符串,格式为xxxx.yyyy.zzzz
|
||||
* @return this
|
||||
*/
|
||||
public JWT parse(String token) {
|
||||
Assert.notBlank(token, "Token String must be not blank!");
|
||||
final List<String> tokens = splitToken(token);
|
||||
this.tokens = tokens;
|
||||
this.header.parse(tokens.get(0), this.charset);
|
||||
this.payload.parse(tokens.get(1), this.charset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return this
|
||||
*/
|
||||
public JWT setCharset(Charset charset) {
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置密钥,如果头部指定了算法,直接使用,否则默认算法是:HS256(HmacSHA256)
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return this
|
||||
*/
|
||||
public JWT setKey(byte[] key) {
|
||||
// 检查头信息中是否有算法信息
|
||||
final String claim = (String) this.header.getClaim(JWTHeader.ALGORITHM);
|
||||
if (StrUtil.isNotBlank(claim)) {
|
||||
return setSigner(JWTSignerUtil.createSigner(claim, key));
|
||||
}
|
||||
return setSigner(JWTSignerUtil.hs256(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置签名算法
|
||||
*
|
||||
* @param algorithmId 签名算法ID,如HS256
|
||||
* @param key 密钥
|
||||
* @return this
|
||||
*/
|
||||
public JWT setSigner(String algorithmId, byte[] key) {
|
||||
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置签名算法
|
||||
*
|
||||
* @param algorithmId 签名算法ID,如HS256
|
||||
* @param key 密钥
|
||||
* @return this
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public JWT setSigner(String algorithmId, Key key) {
|
||||
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置非对称签名算法
|
||||
*
|
||||
* @param algorithmId 签名算法ID,如HS256
|
||||
* @param keyPair 密钥对
|
||||
* @return this
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public JWT setSigner(String algorithmId, KeyPair keyPair) {
|
||||
return setSigner(JWTSignerUtil.createSigner(algorithmId, keyPair));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置签名算法
|
||||
*
|
||||
* @param signer 签名算法
|
||||
* @return this
|
||||
*/
|
||||
public JWT setSigner(JWTSigner signer) {
|
||||
this.signer = signer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JWT算法签名器
|
||||
*
|
||||
* @return JWT算法签名器
|
||||
*/
|
||||
public JWTSigner getSigner() {
|
||||
return this.signer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有头信息
|
||||
*
|
||||
* @return 头信息
|
||||
*/
|
||||
public JSONObject getHeaders() {
|
||||
return this.header.getClaimsJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头
|
||||
*
|
||||
* @return 头信息
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public JWTHeader getHeader() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头信息
|
||||
*
|
||||
* @param name 头信息名称
|
||||
* @return 头信息
|
||||
*/
|
||||
public Object getHeader(String name) {
|
||||
return this.header.getClaim(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取算法ID(alg)头信息
|
||||
*
|
||||
* @return 算法头信息
|
||||
* @see JWTHeader#ALGORITHM
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return (String) this.header.getClaim(JWTHeader.ALGORITHM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置JWT头信息
|
||||
*
|
||||
* @param name 头名
|
||||
* @param value 头
|
||||
* @return this
|
||||
*/
|
||||
public JWT setHeader(String name, Object value) {
|
||||
this.header.setClaim(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加JWT头信息
|
||||
*
|
||||
* @param headers 头信息
|
||||
* @return this
|
||||
*/
|
||||
public JWT addHeaders(Map<String, ?> headers) {
|
||||
this.header.addHeaders(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有载荷信息
|
||||
*
|
||||
* @return 载荷信息
|
||||
*/
|
||||
public JSONObject getPayloads() {
|
||||
return this.payload.getClaimsJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取载荷对象
|
||||
*
|
||||
* @return 载荷信息
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public JWTPayload getPayload() {
|
||||
return this.payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取载荷信息
|
||||
*
|
||||
* @param name 载荷信息名称
|
||||
* @return 载荷信息
|
||||
*/
|
||||
public Object getPayload(String name) {
|
||||
return getPayload().getClaim(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置JWT载荷信息
|
||||
*
|
||||
* @param name 载荷名
|
||||
* @param value 头
|
||||
* @return this
|
||||
*/
|
||||
@Override
|
||||
public JWT setPayload(String name, Object value) {
|
||||
this.payload.setClaim(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加JWT载荷信息
|
||||
*
|
||||
* @param payloads 载荷信息
|
||||
* @return this
|
||||
*/
|
||||
public JWT addPayloads(Map<String, ?> payloads) {
|
||||
this.payload.addPayloads(payloads);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名生成JWT字符串
|
||||
*
|
||||
* @return JWT字符串
|
||||
*/
|
||||
public String sign() {
|
||||
return sign(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名生成JWT字符串
|
||||
*
|
||||
* @param addTypeIfNot 如果'typ'头不存在,是否赋值默认值
|
||||
* @return JWT字符串
|
||||
* @since 5.8.24
|
||||
*/
|
||||
public String sign(boolean addTypeIfNot) {
|
||||
return sign(this.signer, addTypeIfNot);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名生成JWT字符串
|
||||
*
|
||||
* @param signer JWT签名器
|
||||
* @return JWT字符串
|
||||
*/
|
||||
public String sign(JWTSigner signer) {
|
||||
return sign(signer, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名生成JWT字符串
|
||||
*
|
||||
* @param signer JWT签名器
|
||||
* @param addTypeIfNot 如果'typ'头不存在,是否赋值默认值
|
||||
* @return JWT字符串
|
||||
* @since 5.8.24
|
||||
*/
|
||||
public String sign(JWTSigner signer, boolean addTypeIfNot) {
|
||||
Assert.notNull(signer, () -> new JWTException("No Signer provided!"));
|
||||
|
||||
// 检查tye信息
|
||||
if (addTypeIfNot) {
|
||||
final String type = (String) this.header.getClaim(JWTHeader.TYPE);
|
||||
if (StrUtil.isBlank(type)) {
|
||||
this.header.setClaim(JWTHeader.TYPE, "JWT");
|
||||
}
|
||||
}
|
||||
|
||||
// 检查头信息中是否有算法信息
|
||||
final String algorithm = (String) this.header.getClaim(JWTHeader.ALGORITHM);
|
||||
if (StrUtil.isBlank(algorithm)) {
|
||||
this.header.setClaim(JWTHeader.ALGORITHM,
|
||||
AlgorithmUtil.getId(signer.getAlgorithm()));
|
||||
}
|
||||
|
||||
final String headerBase64 = Base64.encodeUrlSafe(this.header.toString(), charset);
|
||||
final String payloadBase64 = Base64.encodeUrlSafe(this.payload.toString(), charset);
|
||||
final String sign = signer.sign(headerBase64, payloadBase64);
|
||||
|
||||
return StrUtil.format("{}.{}.{}", headerBase64, payloadBase64, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JWT Token是否有效
|
||||
*
|
||||
* @return 是否有效
|
||||
*/
|
||||
public boolean verify() {
|
||||
return verify(this.signer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JWT是否有效,验证包括:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Token是否正确</li>
|
||||
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
|
||||
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
|
||||
* <li>{@link JWTPayload#ISSUED_AT}: 签发时间不能晚于当前时间</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
|
||||
* @return 是否有效
|
||||
* @see JWTValidator
|
||||
* @since 5.7.4
|
||||
*/
|
||||
public boolean validate(long leeway) {
|
||||
if (false == verify()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验时间字段
|
||||
try {
|
||||
JWTValidator.of(this).validateDate(DateUtil.date(), leeway);
|
||||
} catch (ValidateException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JWT Token是否有效
|
||||
*
|
||||
* @param signer 签名器(签名算法)
|
||||
* @return 是否有效
|
||||
*/
|
||||
public boolean verify(JWTSigner signer) {
|
||||
if (null == signer) {
|
||||
// 如果无签名器提供,默认认为是无签名JWT信息
|
||||
signer = NoneJWTSigner.NONE;
|
||||
}
|
||||
|
||||
final List<String> tokens = this.tokens;
|
||||
if (CollUtil.isEmpty(tokens)) {
|
||||
throw new JWTException("No token to verify!");
|
||||
}
|
||||
return signer.verify(tokens.get(0), tokens.get(1), tokens.get(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JWT字符串拆分为3部分,无加密算法则最后一部分是""
|
||||
*
|
||||
* @param token JWT Token
|
||||
* @return 三部分内容
|
||||
*/
|
||||
private static List<String> splitToken(String token) {
|
||||
final List<String> tokens = StrUtil.split(token, CharUtil.DOT);
|
||||
if (3 != tokens.size()) {
|
||||
throw new JWTException("The token was expected 3 parts, but got {}.", tokens.size());
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* JWT异常
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class JWTException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JWTException(Throwable e) {
|
||||
super(ExceptionUtil.getMessage(e), e);
|
||||
}
|
||||
|
||||
public JWTException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JWTException(String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params));
|
||||
}
|
||||
|
||||
public JWTException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public JWTException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, throwable, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public JWTException(Throwable throwable, String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params), throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT头部信息
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class JWTHeader extends Claims {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
//Header names
|
||||
/**
|
||||
* 加密算法,通常为HMAC SHA256(HS256)
|
||||
*/
|
||||
public static String ALGORITHM = "alg";
|
||||
/**
|
||||
* 声明类型,一般为jwt
|
||||
*/
|
||||
public static String TYPE = "typ";
|
||||
/**
|
||||
* 内容类型(content type)
|
||||
*/
|
||||
public static String CONTENT_TYPE = "cty";
|
||||
/**
|
||||
* jwk的ID编号
|
||||
*/
|
||||
public static String KEY_ID = "kid";
|
||||
|
||||
/**
|
||||
* 构造,初始化默认(typ=JWT)
|
||||
*/
|
||||
public JWTHeader() {}
|
||||
|
||||
/**
|
||||
* 增加“kid”头信息
|
||||
*
|
||||
* @param keyId kid
|
||||
* @return this
|
||||
*/
|
||||
public JWTHeader setKeyId(String keyId) {
|
||||
setClaim(KEY_ID, keyId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加自定义JWT认证头
|
||||
*
|
||||
* @param headerClaims 头信息
|
||||
* @return this
|
||||
*/
|
||||
public JWTHeader addHeaders(Map<String, ?> headerClaims) {
|
||||
putAll(headerClaims);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT载荷信息<br>
|
||||
* 载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
|
||||
*
|
||||
* <ul>
|
||||
* <li>标准中注册的声明</li>
|
||||
* <li>公共的声明</li>
|
||||
* <li>私有的声明</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 详细介绍见:https://www.jianshu.com/p/576dbf44b2ae
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class JWTPayload extends Claims implements RegisteredPayload<JWTPayload>{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 增加自定义JWT认证载荷信息
|
||||
*
|
||||
* @param payloadClaims 载荷信息
|
||||
* @return this
|
||||
*/
|
||||
public JWTPayload addPayloads(Map<String, ?> payloadClaims) {
|
||||
putAll(payloadClaims);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JWTPayload setPayload(String name, Object value) {
|
||||
setClaim(name, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.exceptions.ValidateException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.util.jwt.signers.JWTSigner;
|
||||
import com.tiesheng.util.jwt.signers.NoneJWTSigner;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JWT数据校验器,用于校验包括:
|
||||
* <ul>
|
||||
* <li>算法是否一致</li>
|
||||
* <li>算法签名是否正确</li>
|
||||
* <li>字段值是否有效(例如时间未过期等)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public class JWTValidator {
|
||||
|
||||
private final JWT jwt;
|
||||
|
||||
/**
|
||||
* 创建JWT验证器
|
||||
*
|
||||
* @param token JWT Token
|
||||
* @return JWTValidator
|
||||
*/
|
||||
public static JWTValidator of(String token) {
|
||||
return new JWTValidator(JWT.of(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建JWT验证器
|
||||
*
|
||||
* @param jwt JWT对象
|
||||
* @return JWTValidator
|
||||
*/
|
||||
public static JWTValidator of(JWT jwt) {
|
||||
return new JWTValidator(jwt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param jwt JWT对象
|
||||
*/
|
||||
public JWTValidator(JWT jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证算法,使用JWT对象自带的{@link JWTSigner}
|
||||
*
|
||||
* @return this
|
||||
* @throws ValidateException 验证失败的异常
|
||||
*/
|
||||
public JWTValidator validateAlgorithm() throws ValidateException {
|
||||
return validateAlgorithm(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证算法,使用自定义的{@link JWTSigner}
|
||||
*
|
||||
* @param signer 用于验证算法的签名器
|
||||
* @return this
|
||||
* @throws ValidateException 验证失败的异常
|
||||
*/
|
||||
public JWTValidator validateAlgorithm(JWTSigner signer) throws ValidateException {
|
||||
validateAlgorithm(this.jwt, signer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查JWT的以下三两个时间:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link JWTPayload#NOT_BEFORE}:被检查时间必须晚于生效时间</li>
|
||||
* <li>{@link JWTPayload#EXPIRES_AT}:被检查时间必须早于失效时间</li>
|
||||
* <li>{@link JWTPayload#ISSUED_AT}:签发时间必须早于失效时间</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 如果某个时间没有设置,则不检查(表示无限制)
|
||||
*
|
||||
* @return this
|
||||
* @throws ValidateException 验证失败的异常
|
||||
* @since 5.7.3
|
||||
*/
|
||||
public JWTValidator validateDate() throws ValidateException {
|
||||
return validateDate(DateUtil.beginOfSecond(DateUtil.date()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查JWT的以下三两个时间:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
|
||||
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
|
||||
* <li>{@link JWTPayload#ISSUED_AT}: 签发时间不能晚于当前时间</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 如果某个时间没有设置,则不检查(表示无限制)
|
||||
*
|
||||
* @param dateToCheck 被检查的时间,一般为当前时间
|
||||
* @return this
|
||||
* @throws ValidateException 验证失败的异常
|
||||
*/
|
||||
public JWTValidator validateDate(Date dateToCheck) throws ValidateException {
|
||||
validateDate(this.jwt.getPayload(), dateToCheck, 0L);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查JWT的以下三两个时间:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
|
||||
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
|
||||
* <li>{@link JWTPayload#ISSUED_AT}: 签发时间不能晚于当前时间</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 如果某个时间没有设置,则不检查(表示无限制)
|
||||
*
|
||||
* @param dateToCheck 被检查的时间,一般为当前时间
|
||||
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
|
||||
* @return this
|
||||
* @throws ValidateException 验证失败的异常
|
||||
*/
|
||||
public JWTValidator validateDate(Date dateToCheck, long leeway) throws ValidateException {
|
||||
validateDate(this.jwt.getPayload(), dateToCheck, leeway);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证算法
|
||||
*
|
||||
* @param jwt {@link JWT}对象
|
||||
* @param signer 用于验证的签名器
|
||||
* @throws ValidateException 验证异常
|
||||
*/
|
||||
private static void validateAlgorithm(JWT jwt, JWTSigner signer) throws ValidateException {
|
||||
final String algorithmId = jwt.getAlgorithm();
|
||||
if (null == signer) {
|
||||
signer = jwt.getSigner();
|
||||
}
|
||||
|
||||
if (StrUtil.isEmpty(algorithmId)) {
|
||||
// 可能无签名
|
||||
if (null == signer || signer instanceof NoneJWTSigner) {
|
||||
return;
|
||||
}
|
||||
throw new ValidateException("No algorithm defined in header!");
|
||||
}
|
||||
|
||||
if (null == signer) {
|
||||
throw new IllegalArgumentException("No Signer for validate algorithm!");
|
||||
}
|
||||
|
||||
final String algorithmIdInSigner = signer.getAlgorithmId();
|
||||
if (false == StrUtil.equals(algorithmId, algorithmIdInSigner)) {
|
||||
throw new ValidateException("Algorithm [{}] defined in header doesn't match to [{}]!"
|
||||
, algorithmId, algorithmIdInSigner);
|
||||
}
|
||||
|
||||
// 通过算法验证签名是否正确
|
||||
if (false == jwt.verify(signer)) {
|
||||
throw new ValidateException("Signature verification failed!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查JWT的以下三两个时间:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
|
||||
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
|
||||
* <li>{@link JWTPayload#ISSUED_AT}: 签发时间不能晚于当前时间</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 如果某个时间没有设置,则不检查(表示无限制)
|
||||
*
|
||||
* @param payload {@link JWTPayload}
|
||||
* @param now 当前时间
|
||||
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
|
||||
* @throws ValidateException 验证异常
|
||||
*/
|
||||
private static void validateDate(JWTPayload payload, Date now, long leeway) throws ValidateException {
|
||||
if (null == now) {
|
||||
// 默认当前时间
|
||||
now = DateUtil.date();
|
||||
// truncate millis
|
||||
now.setTime(now.getTime() / 1000 * 1000);
|
||||
}
|
||||
|
||||
// 检查生效时间(生效时间不能晚于当前时间)
|
||||
final Date notBefore = payload.getClaimsJson().getDate(JWTPayload.NOT_BEFORE);
|
||||
validateNotAfter(JWTPayload.NOT_BEFORE, notBefore, now, leeway);
|
||||
|
||||
// 检查失效时间(失效时间不能早于当前时间)
|
||||
final Date expiresAt = payload.getClaimsJson().getDate(JWTPayload.EXPIRES_AT);
|
||||
validateNotBefore(JWTPayload.EXPIRES_AT, expiresAt, now, leeway);
|
||||
|
||||
// 检查签发时间(签发时间不能晚于当前时间)
|
||||
final Date issueAt = payload.getClaimsJson().getDate(JWTPayload.ISSUED_AT);
|
||||
validateNotAfter(JWTPayload.ISSUED_AT, issueAt, now, leeway);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证指定字段的时间不能晚于当前时间<br>
|
||||
* 被检查的日期不存在则跳过
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param dateToCheck 被检查的字段日期
|
||||
* @param now 当前时间
|
||||
* @param leeway 容忍空间,单位:秒。向后容忍
|
||||
* @throws ValidateException 验证异常
|
||||
*/
|
||||
private static void validateNotAfter(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException {
|
||||
if (null == dateToCheck) {
|
||||
return;
|
||||
}
|
||||
if(leeway > 0){
|
||||
now = DateUtil.date(now.getTime() + leeway * 1000);
|
||||
}
|
||||
if (dateToCheck.after(now)) {
|
||||
throw new ValidateException("'{}':[{}] is after now:[{}]",
|
||||
fieldName, DateUtil.date(dateToCheck), DateUtil.date(now));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证指定字段的时间不能早于当前时间<br>
|
||||
* 被检查的日期不存在则跳过
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param dateToCheck 被检查的字段日期
|
||||
* @param now 当前时间
|
||||
* @param leeway 容忍空间,单位:秒。。向前容忍
|
||||
* @throws ValidateException 验证异常
|
||||
*/
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static void validateNotBefore(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException {
|
||||
if (null == dateToCheck) {
|
||||
return;
|
||||
}
|
||||
if(leeway > 0){
|
||||
now = DateUtil.date(now.getTime() - leeway * 1000);
|
||||
}
|
||||
if (dateToCheck.before(now)) {
|
||||
throw new ValidateException("'{}':[{}] is before now:[{}]",
|
||||
fieldName, DateUtil.date(dateToCheck), DateUtil.date(now));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.tiesheng.util.jwt;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 注册的标准载荷(Payload)声明
|
||||
*
|
||||
* @param <T> 实现此接口的类的类型
|
||||
* @author looly
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public interface RegisteredPayload<T extends RegisteredPayload<T>> {
|
||||
|
||||
/**
|
||||
* jwt签发者
|
||||
*/
|
||||
String ISSUER = "iss";
|
||||
/**
|
||||
* jwt所面向的用户
|
||||
*/
|
||||
String SUBJECT = "sub";
|
||||
/**
|
||||
* 接收jwt的一方
|
||||
*/
|
||||
String AUDIENCE = "aud";
|
||||
/**
|
||||
* jwt的过期时间,这个过期时间必须要大于签发时间
|
||||
*/
|
||||
String EXPIRES_AT = "exp";
|
||||
/**
|
||||
* 生效时间,定义在什么时间之前,该jwt都是不可用的.
|
||||
*/
|
||||
String NOT_BEFORE = "nbf";
|
||||
/**
|
||||
* jwt的签发时间
|
||||
*/
|
||||
String ISSUED_AT = "iat";
|
||||
/**
|
||||
* jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
|
||||
*/
|
||||
String JWT_ID = "jti";
|
||||
|
||||
/**
|
||||
* 设置 jwt签发者("iss")的Payload值
|
||||
*
|
||||
* @param issuer jwt签发者
|
||||
* @return this
|
||||
*/
|
||||
default T setIssuer(String issuer) {
|
||||
return setPayload(ISSUER, issuer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置jwt所面向的用户("sub")的Payload值
|
||||
*
|
||||
* @param subject jwt所面向的用户
|
||||
* @return this
|
||||
*/
|
||||
default T setSubject(String subject) {
|
||||
return setPayload(SUBJECT, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置接收jwt的一方("aud")的Payload值
|
||||
*
|
||||
* @param audience 接收jwt的一方
|
||||
* @return this
|
||||
*/
|
||||
default T setAudience(String... audience) {
|
||||
return setPayload(AUDIENCE, audience);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置jwt的过期时间("exp")的Payload值,这个过期时间必须要大于签发时间
|
||||
*
|
||||
* @param expiresAt jwt的过期时间
|
||||
* @return this
|
||||
* @see #setIssuedAt(Date)
|
||||
*/
|
||||
default T setExpiresAt(Date expiresAt) {
|
||||
return setPayload(EXPIRES_AT, expiresAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置不可用时间点界限("nbf")的Payload值
|
||||
*
|
||||
* @param notBefore 不可用时间点界限,在这个时间点之前,jwt不可用
|
||||
* @return this
|
||||
*/
|
||||
default T setNotBefore(Date notBefore) {
|
||||
return setPayload(NOT_BEFORE, notBefore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置jwt的签发时间("iat")
|
||||
*
|
||||
* @param issuedAt 签发时间
|
||||
* @return this
|
||||
*/
|
||||
default T setIssuedAt(Date issuedAt) {
|
||||
return setPayload(ISSUED_AT, issuedAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置jwt的唯一身份标识("jti")
|
||||
*
|
||||
* @param jwtId 唯一身份标识
|
||||
* @return this
|
||||
*/
|
||||
default T setJWTId(String jwtId) {
|
||||
return setPayload(JWT_ID, jwtId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Payload值
|
||||
*
|
||||
* @param name payload名
|
||||
* @param value payload值
|
||||
* @return this
|
||||
*/
|
||||
T setPayload(String name, Object value);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import cn.hutool.core.map.BiMap;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.asymmetric.SignAlgorithm;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 算法工具类,算法和JWT算法ID对应表
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class AlgorithmUtil {
|
||||
|
||||
private static final BiMap<String, String> map;
|
||||
|
||||
static {
|
||||
map = new BiMap<>(new HashMap<>());
|
||||
map.put("HS256", HmacAlgorithm.HmacSHA256.getValue());
|
||||
map.put("HS384", HmacAlgorithm.HmacSHA384.getValue());
|
||||
map.put("HS512", HmacAlgorithm.HmacSHA512.getValue());
|
||||
|
||||
map.put("HMD5", HmacAlgorithm.HmacMD5.getValue());
|
||||
map.put("HSHA1", HmacAlgorithm.HmacSHA1.getValue());
|
||||
map.put("SM4CMAC", HmacAlgorithm.SM4CMAC.getValue());
|
||||
|
||||
|
||||
map.put("RS256", SignAlgorithm.SHA256withRSA.getValue());
|
||||
map.put("RS384", SignAlgorithm.SHA384withRSA.getValue());
|
||||
map.put("RS512", SignAlgorithm.SHA512withRSA.getValue());
|
||||
|
||||
map.put("ES256", SignAlgorithm.SHA256withECDSA.getValue());
|
||||
map.put("ES384", SignAlgorithm.SHA384withECDSA.getValue());
|
||||
map.put("ES512", SignAlgorithm.SHA512withECDSA.getValue());
|
||||
|
||||
map.put("PS256", SignAlgorithm.SHA256withRSA_PSS.getValue());
|
||||
map.put("PS384", SignAlgorithm.SHA384withRSA_PSS.getValue());
|
||||
map.put("PS512", SignAlgorithm.SHA512withRSA_PSS.getValue());
|
||||
|
||||
map.put("RMD2", SignAlgorithm.MD2withRSA.getValue());
|
||||
map.put("RMD5", SignAlgorithm.MD5withRSA.getValue());
|
||||
map.put("RSHA1", SignAlgorithm.SHA1withRSA.getValue());
|
||||
map.put("DNONE", SignAlgorithm.NONEwithDSA.getValue());
|
||||
map.put("DSHA1", SignAlgorithm.SHA1withDSA.getValue());
|
||||
map.put("ENONE", SignAlgorithm.NONEwithECDSA.getValue());
|
||||
map.put("ESHA1", SignAlgorithm.SHA1withECDSA.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取算法,用户传入算法ID返回算法名,传入算法名返回本身
|
||||
* @param idOrAlgorithm 算法ID或算法名
|
||||
* @return 算法名
|
||||
*/
|
||||
public static String getAlgorithm(String idOrAlgorithm){
|
||||
return ObjectUtil.defaultIfNull(getAlgorithmById(idOrAlgorithm), idOrAlgorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取算法ID,用户传入算法名返回ID,传入算法ID返回本身
|
||||
* @param idOrAlgorithm 算法ID或算法名
|
||||
* @return 算法ID
|
||||
*/
|
||||
public static String getId(String idOrAlgorithm){
|
||||
return ObjectUtil.defaultIfNull(getIdByAlgorithm(idOrAlgorithm), idOrAlgorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据JWT算法ID获取算法
|
||||
*
|
||||
* @param id JWT算法ID
|
||||
* @return 算法
|
||||
*/
|
||||
private static String getAlgorithmById(String id) {
|
||||
return map.get(id.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据算法获取JWT算法ID
|
||||
*
|
||||
* @param algorithm 算法
|
||||
* @return JWT算法ID
|
||||
*/
|
||||
private static String getIdByAlgorithm(String algorithm) {
|
||||
return map.getKey(algorithm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.asymmetric.Sign;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* 非对称加密JWT签名封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class AsymmetricJWTSigner implements JWTSigner {
|
||||
|
||||
private Charset charset = CharsetUtil.CHARSET_UTF_8;
|
||||
private final Sign sign;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm 算法字符串表示
|
||||
* @param key 公钥{@link PublicKey}或私钥{@link PrivateKey},公钥用于验证签名,私钥用于产生签名
|
||||
*/
|
||||
public AsymmetricJWTSigner(String algorithm, Key key) {
|
||||
final PublicKey publicKey = key instanceof PublicKey ? (PublicKey) key : null;
|
||||
final PrivateKey privateKey = key instanceof PrivateKey ? (PrivateKey) key : null;
|
||||
this.sign = new Sign(algorithm, privateKey, publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm 算法字符串表示
|
||||
* @param keyPair 密钥对
|
||||
*/
|
||||
public AsymmetricJWTSigner(String algorithm, KeyPair keyPair) {
|
||||
this.sign = new Sign(algorithm, keyPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return 编码
|
||||
*/
|
||||
public AsymmetricJWTSigner setCharset(Charset charset) {
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sign(String headerBase64, String payloadBase64) {
|
||||
final String dataStr = StrUtil.format("{}.{}", headerBase64, payloadBase64);
|
||||
return Base64.encodeUrlSafe(sign(StrUtil.bytes(dataStr, charset)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名字符串数据
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 签名
|
||||
*/
|
||||
protected byte[] sign(byte[] data) {
|
||||
return sign.sign(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
|
||||
return verify(
|
||||
StrUtil.bytes(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset),
|
||||
Base64.decode(signBase64));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验签数据
|
||||
*
|
||||
* @param data 数据
|
||||
* @param signed 签名
|
||||
* @return 是否通过
|
||||
*/
|
||||
protected boolean verify(byte[] data, byte[] signed) {
|
||||
return sign.verify(data, signed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return this.sign.getSignature().getAlgorithm();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import com.tiesheng.util.jwt.JWTException;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
|
||||
/**
|
||||
* 椭圆曲线(Elliptic Curve)的JWT签名器。<br>
|
||||
* 按照https://datatracker.ietf.org/doc/html/rfc7518#section-3.4,<br>
|
||||
* Elliptic Curve Digital Signature Algorithm (ECDSA)算法签名需要转换DER格式为pair (R, S)
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.21
|
||||
*/
|
||||
public class EllipticCurveJWTSigner extends AsymmetricJWTSigner {
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm 算法
|
||||
* @param key 密钥
|
||||
*/
|
||||
public EllipticCurveJWTSigner(String algorithm, Key key) {
|
||||
super(algorithm, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm 算法
|
||||
* @param keyPair 密钥对
|
||||
*/
|
||||
public EllipticCurveJWTSigner(String algorithm, KeyPair keyPair) {
|
||||
super(algorithm, keyPair);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] sign(final byte[] data) {
|
||||
// https://datatracker.ietf.org/doc/html/rfc7518#section-3.4
|
||||
return derToConcat(super.sign(data), getSignatureByteArrayLength(getAlgorithm()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean verify(final byte[] data, final byte[] signed) {
|
||||
// https://datatracker.ietf.org/doc/html/rfc7518#section-3.4
|
||||
return super.verify(data, concatToDER(signed));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取签名长度
|
||||
* @param alg 算法
|
||||
* @return 长度
|
||||
* @throws JWTException JWT异常
|
||||
*/
|
||||
private static int getSignatureByteArrayLength(final String alg) throws JWTException {
|
||||
switch (alg) {
|
||||
case "ES256":
|
||||
case "SHA256withECDSA":
|
||||
return 64;
|
||||
case "ES384":
|
||||
case "SHA384withECDSA":
|
||||
return 96;
|
||||
case "ES512":
|
||||
case "SHA512withECDSA":
|
||||
return 132;
|
||||
default:
|
||||
throw new JWTException("Unsupported Algorithm: {}", alg);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] derToConcat(final byte[] derSignature, int outputLength) throws JWTException {
|
||||
|
||||
if (derSignature.length < 8 || derSignature[0] != 48) {
|
||||
throw new JWTException("Invalid ECDSA signature format");
|
||||
}
|
||||
|
||||
final int offset;
|
||||
if (derSignature[1] > 0) {
|
||||
offset = 2;
|
||||
} else if (derSignature[1] == (byte) 0x81) {
|
||||
offset = 3;
|
||||
} else {
|
||||
throw new JWTException("Invalid ECDSA signature format");
|
||||
}
|
||||
|
||||
final byte rLength = derSignature[offset + 1];
|
||||
|
||||
int i = rLength;
|
||||
while ((i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0)) {
|
||||
i--;
|
||||
}
|
||||
|
||||
final byte sLength = derSignature[offset + 2 + rLength + 1];
|
||||
|
||||
int j = sLength;
|
||||
while ((j > 0) && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0)) {
|
||||
j--;
|
||||
}
|
||||
|
||||
int rawLen = Math.max(i, j);
|
||||
rawLen = Math.max(rawLen, outputLength / 2);
|
||||
|
||||
if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
|
||||
|| (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
|
||||
|| derSignature[offset] != 2
|
||||
|| derSignature[offset + 2 + rLength] != 2) {
|
||||
throw new JWTException("Invalid ECDSA signature format");
|
||||
}
|
||||
|
||||
final byte[] concatSignature = new byte[2 * rawLen];
|
||||
|
||||
System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i);
|
||||
System.arraycopy(derSignature, (offset + 2 + rLength + 2 + sLength) - j, concatSignature, 2 * rawLen - j, j);
|
||||
|
||||
return concatSignature;
|
||||
}
|
||||
|
||||
private static byte[] concatToDER(byte[] jwsSignature) throws ArrayIndexOutOfBoundsException {
|
||||
|
||||
int rawLen = jwsSignature.length / 2;
|
||||
|
||||
int i = rawLen;
|
||||
|
||||
while ((i > 0) && (jwsSignature[rawLen - i] == 0)) {
|
||||
i--;
|
||||
}
|
||||
|
||||
int j = i;
|
||||
|
||||
if (jwsSignature[rawLen - i] < 0) {
|
||||
j += 1;
|
||||
}
|
||||
|
||||
int k = rawLen;
|
||||
|
||||
while ((k > 0) && (jwsSignature[2 * rawLen - k] == 0)) {
|
||||
k--;
|
||||
}
|
||||
|
||||
int l = k;
|
||||
|
||||
if (jwsSignature[2 * rawLen - k] < 0) {
|
||||
l += 1;
|
||||
}
|
||||
|
||||
int len = 2 + j + 2 + l;
|
||||
|
||||
if (len > 255) {
|
||||
throw new JWTException("Invalid ECDSA signature format");
|
||||
}
|
||||
|
||||
int offset;
|
||||
|
||||
final byte[] derSignature;
|
||||
|
||||
if (len < 128) {
|
||||
derSignature = new byte[2 + 2 + j + 2 + l];
|
||||
offset = 1;
|
||||
} else {
|
||||
derSignature = new byte[3 + 2 + j + 2 + l];
|
||||
derSignature[1] = (byte) 0x81;
|
||||
offset = 2;
|
||||
}
|
||||
|
||||
derSignature[0] = 48;
|
||||
derSignature[offset++] = (byte) len;
|
||||
derSignature[offset++] = 2;
|
||||
derSignature[offset++] = (byte) j;
|
||||
|
||||
System.arraycopy(jwsSignature, rawLen - i, derSignature, (offset + j) - i, i);
|
||||
|
||||
offset += j;
|
||||
|
||||
derSignature[offset++] = 2;
|
||||
derSignature[offset++] = (byte) l;
|
||||
|
||||
System.arraycopy(jwsSignature, 2 * rawLen - k, derSignature, (offset + l) - k, k);
|
||||
|
||||
return derSignature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.HMac;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* HMac算法签名实现
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class HMacJWTSigner implements JWTSigner {
|
||||
|
||||
private Charset charset = CharsetUtil.CHARSET_UTF_8;
|
||||
private final HMac hMac;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm HMAC签名算法
|
||||
* @param key 密钥
|
||||
*/
|
||||
public HMacJWTSigner(String algorithm, byte[] key) {
|
||||
this.hMac = new HMac(algorithm, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm HMAC签名算法
|
||||
* @param key 密钥
|
||||
*/
|
||||
public HMacJWTSigner(String algorithm, Key key) {
|
||||
this.hMac = new HMac(algorithm, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return 编码
|
||||
*/
|
||||
public HMacJWTSigner setCharset(Charset charset) {
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sign(String headerBase64, String payloadBase64) {
|
||||
return hMac.digestBase64(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
|
||||
final String sign = sign(headerBase64, payloadBase64);
|
||||
return hMac.verify(
|
||||
StrUtil.bytes(sign, charset),
|
||||
StrUtil.bytes(signBase64, charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return this.hMac.getAlgorithm();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
/**
|
||||
* JWT签名接口封装,通过实现此接口,完成不同算法的签名功能
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public interface JWTSigner {
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*
|
||||
* @param headerBase64 JWT头的JSON字符串的Base64表示
|
||||
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
|
||||
* @return 签名结果Base64,即JWT的第三部分
|
||||
*/
|
||||
String sign(String headerBase64, String payloadBase64);
|
||||
|
||||
/**
|
||||
* 验签
|
||||
*
|
||||
* @param headerBase64 JWT头的JSON字符串Base64表示
|
||||
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
|
||||
* @param signBase64 被验证的签名Base64表示
|
||||
* @return 签名是否一致
|
||||
*/
|
||||
boolean verify(String headerBase64, String payloadBase64, String signBase64);
|
||||
|
||||
/**
|
||||
* 获取算法
|
||||
*
|
||||
* @return 算法
|
||||
*/
|
||||
String getAlgorithm();
|
||||
|
||||
/**
|
||||
* 获取算法ID,即算法的简写形式,如HS256
|
||||
*
|
||||
* @return 算法ID
|
||||
* @since 5.7.2
|
||||
*/
|
||||
default String getAlgorithmId() {
|
||||
return AlgorithmUtil.getId(getAlgorithm());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* JWT签名器工具类
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class JWTSignerUtil {
|
||||
|
||||
/**
|
||||
* 无签名
|
||||
*
|
||||
* @return 无签名的签名器
|
||||
*/
|
||||
public static JWTSigner none() {
|
||||
return NoneJWTSigner.NONE;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------- HSxxx
|
||||
|
||||
/**
|
||||
* HS256(HmacSHA256)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner hs256(byte[] key) {
|
||||
return createSigner("HS256", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HS384(HmacSHA384)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner hs384(byte[] key) {
|
||||
return createSigner("HS384", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HS512(HmacSHA512)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner hs512(byte[] key) {
|
||||
return createSigner("HS512", key);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------- RSxxx
|
||||
|
||||
/**
|
||||
* RS256(SHA256withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rs256(Key key) {
|
||||
return createSigner("RS256", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* RS384(SHA384withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rs384(Key key) {
|
||||
return createSigner("RS384", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* RS512(SHA512withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rs512(Key key) {
|
||||
return createSigner("RS512", key);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------- ESxxx
|
||||
|
||||
/**
|
||||
* ES256(SHA256withECDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner es256(Key key) {
|
||||
return createSigner("ES256", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* ES384(SHA383withECDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner es384(Key key) {
|
||||
return createSigner("ES384", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* ES512(SHA512withECDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner es512(Key key) {
|
||||
return createSigner("ES512", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMD5(HmacMD5)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner hmd5(Key key) {
|
||||
return createSigner("HMD5",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HSHA1(HmacSHA1)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner hsha1(Key key) {
|
||||
return createSigner("HSHA1",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* SM4CMAC(SM4CMAC)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner sm4cmac(Key key) {
|
||||
return createSigner("SM4CMAC",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* RMD2(MD2withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rmd2(Key key) {
|
||||
return createSigner("RMD2",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* RMD5(MD5withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rmd5(Key key) {
|
||||
return createSigner("RMD5",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSHA1(SHA1withRSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner rsha1(Key key) {
|
||||
return createSigner("RSHA1",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* DNONE(NONEwithDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner dnone(Key key) {
|
||||
return createSigner("DNONE",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* DSHA1(SHA1withDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner dsha1(Key key) {
|
||||
return createSigner("DSHA1",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* ENONE(NONEwithECDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner enone(Key key) {
|
||||
return createSigner("ENONE",key);
|
||||
}
|
||||
|
||||
/**
|
||||
* ESHA1(SHA1withECDSA)签名器
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner esha1(Key key) {
|
||||
return createSigner("ESHA1",key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 创建签名器
|
||||
*
|
||||
* @param algorithmId 算法ID,见{@link AlgorithmUtil}
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner createSigner(String algorithmId, byte[] key) {
|
||||
Assert.notNull(key, "Signer key must be not null!");
|
||||
|
||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
||||
return none();
|
||||
}
|
||||
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建签名器
|
||||
*
|
||||
* @param algorithmId 算法ID,见{@link AlgorithmUtil}
|
||||
* @param keyPair 密钥对
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner createSigner(String algorithmId, KeyPair keyPair) {
|
||||
Assert.notNull(keyPair, "Signer key pair must be not null!");
|
||||
|
||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
||||
return none();
|
||||
}
|
||||
|
||||
// issue3205@Github
|
||||
if(ReUtil.isMatch("es\\d{3}", algorithmId.toLowerCase())){
|
||||
return new EllipticCurveJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), keyPair);
|
||||
}
|
||||
|
||||
return new AsymmetricJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), keyPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建签名器
|
||||
*
|
||||
* @param algorithmId 算法ID,见{@link AlgorithmUtil}
|
||||
* @param key 密钥
|
||||
* @return 签名器
|
||||
*/
|
||||
public static JWTSigner createSigner(String algorithmId, Key key) {
|
||||
Assert.notNull(key, "Signer key must be not null!");
|
||||
|
||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
||||
return NoneJWTSigner.NONE;
|
||||
}
|
||||
if (key instanceof PrivateKey || key instanceof PublicKey) {
|
||||
// issue3205@Github
|
||||
if(ReUtil.isMatch("ES\\d{3}", algorithmId)){
|
||||
return new EllipticCurveJWTSigner(algorithmId, key);
|
||||
}
|
||||
|
||||
return new AsymmetricJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
|
||||
}
|
||||
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.tiesheng.util.jwt.signers;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* 无需签名的JWT签名器
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public class NoneJWTSigner implements JWTSigner {
|
||||
|
||||
public static final String ID_NONE = "none";
|
||||
|
||||
public static NoneJWTSigner NONE = new NoneJWTSigner();
|
||||
|
||||
@Override
|
||||
public String sign(String headerBase64, String payloadBase64) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
|
||||
return StrUtil.isEmpty(signBase64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return ID_NONE;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package com.tiesheng.util.pojos;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import com.tiesheng.util.config.TsTokenConfig;
|
||||
import com.tiesheng.util.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.tiesheng.util.service;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.service.cache.TsCacheHandler;
|
||||
@@ -36,7 +36,7 @@ public class TsCacheService {
|
||||
}
|
||||
|
||||
public void putObj(String key, Object value, long seconds) {
|
||||
tsCacheHandler.put(key, JSONUtil.toJsonStr(value), seconds);
|
||||
tsCacheHandler.put(key, JSON.toJSONString(value), seconds);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
@@ -58,7 +58,7 @@ public class TsCacheService {
|
||||
* @return
|
||||
*/
|
||||
public <T> T getObj(String key, Class<T> tClass, long seconds) {
|
||||
return JSONUtil.toBean(get(key, seconds), tClass, true);
|
||||
return JSON.parseObject(get(key, seconds), tClass);
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tiesheng.util.service.cache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@@ -13,7 +14,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@ConditionalOnProperty("spring.redis.url")
|
||||
public class TsCacheRedisHandler implements TsCacheHandler {
|
||||
|
||||
@Resource
|
||||
@Autowired
|
||||
RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -30,4 +30,12 @@ public interface TsAuthorityHandler {
|
||||
*/
|
||||
List<String> getAuthorities(TokenBean tokenBean);
|
||||
|
||||
|
||||
/**
|
||||
* 创建结束后
|
||||
*
|
||||
* @param version
|
||||
*/
|
||||
void onCreateAfter(String version);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>2.0.0.rc25</version>
|
||||
<version>2.0.0.rc44</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-web</artifactId>
|
||||
|
||||
@@ -2,12 +2,13 @@ package com.tiesheng.web.config.exception;
|
||||
|
||||
import cn.hutool.core.exceptions.ValidateException;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.tiesheng.web.service.TieshengWebConfigurer;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.exception.ApiRespEnum;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
import com.tiesheng.web.service.TieshengWebConfigurer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
@@ -55,6 +56,9 @@ public class SpringExceptionHandler {
|
||||
}
|
||||
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), msg);
|
||||
}
|
||||
if (e instanceof HttpMessageNotReadableException) {
|
||||
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), "参数格式不正确");
|
||||
}
|
||||
if (e instanceof MethodArgumentTypeMismatchException) {
|
||||
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), "请求参数不合法");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.tiesheng.web.config.json;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.tiesheng.util.CommonUtil;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -25,12 +26,15 @@ public class FastJsonMessageConverter {
|
||||
@Bean
|
||||
public HttpMessageConverters fastJsonHttpMessageConverters() {
|
||||
|
||||
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
|
||||
fastConverter.setFastJsonConfig(CommonUtil.fastJsonConfig());
|
||||
fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat(JSON.DEFFAULT_DATE_FORMAT);
|
||||
|
||||
List<MediaType> mediaTypes = new ArrayList<>();
|
||||
mediaTypes.add(MediaType.APPLICATION_JSON);
|
||||
|
||||
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
|
||||
fastConverter.setFastJsonConfig(config);
|
||||
fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
fastConverter.setSupportedMediaTypes(mediaTypes);
|
||||
|
||||
return new HttpMessageConverters(fastConverter);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.tiesheng.web.config.role;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.tiesheng.annotation.role.RoleAuthority;
|
||||
import com.tiesheng.util.service.role.TsAuthorityHandler;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class RoleAuthorityCreator implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
@Resource
|
||||
TsAuthorityHandler tsAuthorityHandler;
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
Map<String, Object> beansOfType = applicationContext.getBeansWithAnnotation(RoleAuthority.class);
|
||||
|
||||
String version = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||
|
||||
for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
|
||||
|
||||
Class<?> targetClass = AopUtils.getTargetClass(entry.getValue());
|
||||
RoleAuthority menu = targetClass.getAnnotation(RoleAuthority.class);
|
||||
|
||||
List<RoleAuthority> points = new ArrayList<>();
|
||||
Method[] methods = targetClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
RoleAuthority methodAuthority = AnnotationUtil.getAnnotation(method, RoleAuthority.class);
|
||||
if (methodAuthority != null) {
|
||||
points.add(methodAuthority);
|
||||
}
|
||||
}
|
||||
|
||||
tsAuthorityHandler.addRoleAuthority(version, menu, points);
|
||||
}
|
||||
|
||||
tsAuthorityHandler.onCreateAfter(version);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.tiesheng.web.config.template;
|
||||
|
||||
import com.tiesheng.web.pojos.dto.TemplateDealDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class TieshengTemplateHandler implements ToolTemplateHandler {
|
||||
@Override
|
||||
public String handler(TemplateDealDTO dto) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateUrl() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParms(Object params) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAction() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.tiesheng.web.config.template;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.web.pojos.dto.TemplateDealDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public interface ToolTemplateHandler {
|
||||
|
||||
|
||||
/**
|
||||
* 处理对象
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
String handler(TemplateDealDTO dto);
|
||||
|
||||
|
||||
/**
|
||||
* 获取模版地址
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getTemplateUrl();
|
||||
|
||||
Object getParms(Object params);
|
||||
|
||||
|
||||
/**
|
||||
* 动作说明(唯一)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getAction();
|
||||
|
||||
|
||||
/**
|
||||
* 排序,如果action相同,只会使用sort大的来处理
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getSort();
|
||||
|
||||
/**
|
||||
* 获取模版ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default String getTeamplateId() {
|
||||
return StrUtil.format("{}_{}", getAction(), getSort());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,19 +4,33 @@ package com.tiesheng.web.controller.comm;
|
||||
import cn.hutool.captcha.LineCaptcha;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tiesheng.annotation.operation.OperationIgnore;
|
||||
import com.tiesheng.annotation.token.TokenIgnore;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
import com.tiesheng.web.config.template.ToolTemplateHandler;
|
||||
import com.tiesheng.web.pojos.dto.*;
|
||||
import com.tiesheng.web.pojos.vo.TemplateInfoVO;
|
||||
import com.tiesheng.web.pojos.vo.PicVerifyVo;
|
||||
import com.tiesheng.web.service.FileUploadService;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.util.service.TsCacheService;
|
||||
import com.tiesheng.web.pojos.dao.CoreLogProcess;
|
||||
import com.tiesheng.web.pojos.dto.ChunkCheckDTO;
|
||||
import com.tiesheng.web.pojos.dto.ChunkMergeDTO;
|
||||
import com.tiesheng.web.pojos.dto.ChunkStartDTO;
|
||||
import com.tiesheng.web.pojos.dto.ImageCodeDTO;
|
||||
import com.tiesheng.web.pojos.imex.ExportDealDTO;
|
||||
import com.tiesheng.web.pojos.imex.ImportDealDTO;
|
||||
import com.tiesheng.web.pojos.imex.ImportInfoDTO;
|
||||
import com.tiesheng.web.pojos.imex.ImportInfoVO;
|
||||
import com.tiesheng.web.pojos.vo.PicVerifyVo;
|
||||
import com.tiesheng.web.service.CoreLogService;
|
||||
import com.tiesheng.web.service.FileUploadService;
|
||||
import com.tiesheng.web.service.imex.TsExportHandler;
|
||||
import com.tiesheng.web.service.imex.TsImportHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -35,7 +49,11 @@ public class ToolController {
|
||||
@Autowired
|
||||
FileUploadService fileUploadService;
|
||||
@Autowired
|
||||
List<ToolTemplateHandler> templateHandlerList;
|
||||
List<TsImportHandler> importHandlers;
|
||||
@Autowired
|
||||
List<TsExportHandler> exportHandlers;
|
||||
@Autowired
|
||||
CoreLogService coreLogService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -124,40 +142,102 @@ public class ToolController {
|
||||
}
|
||||
|
||||
|
||||
@TokenIgnore
|
||||
@GetMapping("/template/info")
|
||||
public ApiResp<TemplateInfoVO> templateInfo(TemplateInfoDTO dto) {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// import
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
List<ToolTemplateHandler> collect = templateHandlerList.stream()
|
||||
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
|
||||
.sorted((it, it2) -> it2.getSort() - it.getSort())
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(collect)) {
|
||||
throw new ApiException("没有找到对应的模版");
|
||||
@TokenIgnore
|
||||
@GetMapping("/imex/info")
|
||||
public ApiResp<ImportInfoVO> importInfo(@Valid ImportInfoDTO dto) {
|
||||
|
||||
ImportInfoVO template = new ImportInfoVO();
|
||||
|
||||
if (Objects.equals(dto.getType(), "import")) {
|
||||
List<TsImportHandler> collect = importHandlers.stream()
|
||||
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
|
||||
.sorted((it, it2) -> it2.getSort() - it.getSort())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollUtil.isNotEmpty(collect)) {
|
||||
TsImportHandler toolTemplateHandler = collect.get(0);
|
||||
template.setTemplateUrl(toolTemplateHandler.getTemplateUrl());
|
||||
template.setImexId(toolTemplateHandler.getImexId());
|
||||
}
|
||||
} else if (Objects.equals(dto.getType(), "export")) {
|
||||
List<TsExportHandler> collect = exportHandlers.stream()
|
||||
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
|
||||
.sorted((it, it2) -> it2.getSort() - it.getSort())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollUtil.isNotEmpty(collect)) {
|
||||
TsExportHandler toolTemplateHandler = collect.get(0);
|
||||
template.setImexId(toolTemplateHandler.getImexId());
|
||||
}
|
||||
}
|
||||
|
||||
ToolTemplateHandler toolTemplateHandler = collect.get(0);
|
||||
|
||||
TemplateInfoVO template = new TemplateInfoVO();
|
||||
template.setTemplateUrl(toolTemplateHandler.getTemplateUrl());
|
||||
template.setParams(toolTemplateHandler.getParms(dto.getParams()));
|
||||
template.setTemplateId(toolTemplateHandler.getTeamplateId());
|
||||
if (StrUtil.isEmpty(template.getImexId())) {
|
||||
throw new ApiException("没有找到对应的模版");
|
||||
}
|
||||
|
||||
return ApiResp.respOK(template);
|
||||
}
|
||||
|
||||
@TokenIgnore
|
||||
@PostMapping("/template/deal")
|
||||
public ApiResp<String> templateDeal(@RequestBody TemplateDealDTO dto) {
|
||||
|
||||
List<ToolTemplateHandler> collect = templateHandlerList.stream().
|
||||
filter(it -> Objects.equals(it.getTeamplateId(), dto.getTemplateId()))
|
||||
@TokenIgnore
|
||||
@OperationIgnore
|
||||
@PostMapping("/import/deal")
|
||||
public ApiResp<String> importDeal(@RequestBody @Valid ImportDealDTO dto, TokenBean token) {
|
||||
|
||||
List<TsImportHandler> collect = importHandlers.stream().
|
||||
filter(it -> Objects.equals(it.getImexId(), dto.getImexId()))
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(collect)) {
|
||||
throw new ApiException("模版ID不存在");
|
||||
throw new ApiException("导入ID不存在");
|
||||
}
|
||||
|
||||
return ApiResp.respOK(collect.get(0).handler(dto));
|
||||
TsImportHandler tsImportHandler = collect.get(0);
|
||||
tsImportHandler.validToken(token);
|
||||
List read = tsImportHandler.ready(dto, token);
|
||||
if (CollUtil.isEmpty(read)) {
|
||||
throw new ApiException("没有数据可以导入");
|
||||
}
|
||||
CoreLogProcess coreLogProcess = coreLogService.addProcess(tsImportHandler.getImexId(), read, tsImportHandler);
|
||||
coreLogProcess.setParams(JSON.toJSONString(dto));
|
||||
coreLogService.getCoreLogProcessMapper().updateById(coreLogProcess);
|
||||
|
||||
return ApiResp.respOK(coreLogProcess.getId());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// export
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@TokenIgnore
|
||||
@OperationIgnore
|
||||
@PostMapping("/export/deal")
|
||||
public ApiResp<String> exportDeal(@RequestBody @Valid ExportDealDTO dto, TokenBean token) {
|
||||
|
||||
List<TsExportHandler> collect = exportHandlers.stream().
|
||||
filter(it -> Objects.equals(it.getImexId(), dto.getImexId()))
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(collect)) {
|
||||
throw new ApiException("导出ID不存在");
|
||||
}
|
||||
|
||||
TsExportHandler tsExportHandler = collect.get(0);
|
||||
tsExportHandler.validToken(token);
|
||||
List read = tsExportHandler.ready(dto, token);
|
||||
if (CollUtil.isEmpty(read)) {
|
||||
throw new ApiException("没有数据可以导出");
|
||||
}
|
||||
CoreLogProcess coreLogProcess = coreLogService.addProcess(tsExportHandler.getImexId(), read, tsExportHandler);
|
||||
coreLogProcess.setType("export");
|
||||
coreLogProcess.setParams(JSON.toJSONString(dto));
|
||||
coreLogService.getCoreLogProcessMapper().updateById(coreLogProcess);
|
||||
|
||||
return ApiResp.respOK(coreLogProcess.getId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -51,18 +51,18 @@ public class CoreLogProcess extends DaoBase {
|
||||
@TableField(value = "fail_file")
|
||||
private String failFile;
|
||||
|
||||
/**
|
||||
* 异常说明
|
||||
*/
|
||||
@TableField(value = "error")
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 进度
|
||||
*/
|
||||
@TableField(value = "`process`")
|
||||
private Integer process;
|
||||
|
||||
/**
|
||||
* 异常说明
|
||||
*/
|
||||
@TableField(value = "params")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 获取标题
|
||||
*
|
||||
@@ -189,24 +189,6 @@ public class CoreLogProcess extends DaoBase {
|
||||
this.failFile = failFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常说明
|
||||
*
|
||||
* @return error - 异常说明
|
||||
*/
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置异常说明
|
||||
*
|
||||
* @param error 异常说明
|
||||
*/
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取进度
|
||||
*
|
||||
@@ -224,4 +206,22 @@ public class CoreLogProcess extends DaoBase {
|
||||
public void setProcess(Integer process) {
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常说明
|
||||
*
|
||||
* @return params - 异常说明
|
||||
*/
|
||||
public String getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置异常说明
|
||||
*
|
||||
* @param params 异常说明
|
||||
*/
|
||||
public void setParams(String params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.tiesheng.web.pojos.imex;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
public class ExportDealDTO {
|
||||
|
||||
@NotEmpty(message = "模版ID")
|
||||
private String imexId;
|
||||
private JSONObject params;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public String getImexId() {
|
||||
return imexId;
|
||||
}
|
||||
|
||||
public void setImexId(String imexId) {
|
||||
this.imexId = imexId;
|
||||
}
|
||||
|
||||
public JSONObject getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(JSONObject params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,27 @@
|
||||
package com.tiesheng.web.pojos.dto;
|
||||
package com.tiesheng.web.pojos.imex;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
public class TemplateDealDTO {
|
||||
public class ImportDealDTO {
|
||||
|
||||
@NotEmpty(message = "模版ID")
|
||||
private String templateId;
|
||||
private String imexId;
|
||||
@NotEmpty(message = "文件路径必填")
|
||||
private String file;
|
||||
private Object params;
|
||||
private JSONObject params;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getTemplateId() {
|
||||
return templateId;
|
||||
public String getImexId() {
|
||||
return imexId;
|
||||
}
|
||||
|
||||
public void setTemplateId(String templateId) {
|
||||
this.templateId = templateId;
|
||||
public void setImexId(String imexId) {
|
||||
this.imexId = imexId;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
@@ -30,11 +32,11 @@ public class TemplateDealDTO {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Object getParams() {
|
||||
public JSONObject getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(Object params) {
|
||||
public void setParams(JSONObject params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
package com.tiesheng.web.pojos.dto;
|
||||
package com.tiesheng.web.pojos.imex;
|
||||
|
||||
|
||||
public class TemplateInfoDTO {
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
public class ImportInfoDTO {
|
||||
|
||||
@NotEmpty(message = "操作必须存在")
|
||||
private String action;
|
||||
private Object params;
|
||||
|
||||
@NotEmpty(message = "类型必须存在")
|
||||
private String type;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
@@ -18,11 +23,11 @@ public class TemplateInfoDTO {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public Object getParams() {
|
||||
return params;
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setParams(Object params) {
|
||||
this.params = params;
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.tiesheng.web.pojos.imex;
|
||||
|
||||
|
||||
public class ImportInfoVO {
|
||||
|
||||
private String imexId;
|
||||
private String templateUrl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getImexId() {
|
||||
return imexId;
|
||||
}
|
||||
|
||||
public void setImexId(String imexId) {
|
||||
this.imexId = imexId;
|
||||
}
|
||||
|
||||
public String getTemplateUrl() {
|
||||
return templateUrl;
|
||||
}
|
||||
|
||||
public void setTemplateUrl(String templateUrl) {
|
||||
this.templateUrl = templateUrl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.tiesheng.web.pojos.vo;
|
||||
|
||||
|
||||
public class TemplateInfoVO {
|
||||
|
||||
private String templateId;
|
||||
private String templateUrl;
|
||||
private Object params;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getTemplateId() {
|
||||
return templateId;
|
||||
}
|
||||
|
||||
public void setTemplateId(String templateId) {
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
||||
public String getTemplateUrl() {
|
||||
return templateUrl;
|
||||
}
|
||||
|
||||
public void setTemplateUrl(String templateUrl) {
|
||||
this.templateUrl = templateUrl;
|
||||
}
|
||||
|
||||
public Object getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(Object params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.tiesheng.login.mapper.CoreLogLoginMapper;
|
||||
import com.tiesheng.login.pojos.RequestUserInfo;
|
||||
@@ -79,33 +79,24 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
coreLogProcess.setSuccessNum(0);
|
||||
coreLogProcess.setFailNum(0);
|
||||
coreLogProcess.setProcess(0);
|
||||
coreLogProcess.setError("");
|
||||
coreLogProcess.setParams("");
|
||||
coreLogProcessMapper.insert(coreLogProcess);
|
||||
|
||||
ThreadUtil.execute(() -> {
|
||||
List<Exception> errorList = new ArrayList<>();
|
||||
CollUtil.split(list, 100).forEach((it) -> {
|
||||
int accept = 0;
|
||||
try {
|
||||
accept = consumer.accept(it);
|
||||
} catch (Exception e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
int accept = consumer.batchHandler(it);
|
||||
coreLogProcess.setProcess(coreLogProcess.getProcess() + it.size());
|
||||
coreLogProcess.setSuccessNum(coreLogProcess.getSuccessNum() + accept);
|
||||
coreLogProcess.setFailNum(coreLogProcess.getFailNum() + it.size() - accept);
|
||||
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
|
||||
coreLogProcessMapper.updateById(coreLogProcess);
|
||||
});
|
||||
|
||||
// 执行结束
|
||||
coreLogProcess.setFailFile(consumer.getFailFile());
|
||||
coreLogProcess.setStatus(1);
|
||||
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
|
||||
coreLogProcessMapper.updateById(coreLogProcess);
|
||||
});
|
||||
|
||||
|
||||
return coreLogProcess;
|
||||
}
|
||||
|
||||
@@ -126,29 +117,24 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
coreLogProcess.setFailNum(0);
|
||||
coreLogProcess.setTotal(0);
|
||||
coreLogProcess.setProcess(0);
|
||||
coreLogProcess.setError("");
|
||||
coreLogProcessMapper.insert(coreLogProcess);
|
||||
|
||||
ThreadUtil.execute(() -> {
|
||||
int pageSize = 1000;
|
||||
int pageNum = 1, lastCount = pageSize;
|
||||
List<Exception> errorList = new ArrayList<>();
|
||||
while (lastCount == pageSize) {
|
||||
try {
|
||||
lastCount = consumer.accept(pageNum, pageSize);
|
||||
coreLogProcess.setTotal(coreLogProcess.getTotal() + lastCount);
|
||||
coreLogProcess.setProcess(coreLogProcess.getTotal());
|
||||
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
|
||||
coreLogProcess.setSuccessNum(coreLogProcess.getSuccessNum() + lastCount);
|
||||
} catch (Exception e) {
|
||||
errorList.add(e);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
coreLogProcessMapper.updateById(coreLogProcess);
|
||||
pageNum++;
|
||||
}
|
||||
|
||||
// 执行结束
|
||||
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
|
||||
coreLogProcess.setStatus(1);
|
||||
coreLogProcessMapper.updateById(coreLogProcess);
|
||||
});
|
||||
@@ -179,7 +165,7 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
if (tokenBean == null || StrUtil.isEmpty(tokenBean.getId())) {
|
||||
return;
|
||||
}
|
||||
RequestUserInfo requestUserInfo = tieshengWebConfigurer.configureLogin().getCachedUserInfo(tokenBean);
|
||||
RequestUserInfo requestUserInfo = tieshengWebConfigurer.configureLogin().getCachedUserInfo(tokenBean, false);
|
||||
if (requestUserInfo == null) {
|
||||
return;
|
||||
}
|
||||
@@ -192,7 +178,7 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
operation.setTitle(title);
|
||||
operation.setSubject(subject);
|
||||
if (params != null) {
|
||||
operation.setParams(JSONUtil.toJsonStr(params));
|
||||
operation.setParams(JSON.toJSONString(params));
|
||||
}
|
||||
|
||||
synchronized (CoreLogOperation.class) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.tiesheng.web.service;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tiesheng.util.service.http.OkHttpUtil;
|
||||
import com.tiesheng.web.mapper.CoreLogApiMapper;
|
||||
import com.tiesheng.web.pojos.dao.CoreLogApi;
|
||||
@@ -38,11 +37,13 @@ public class LogApiOkHttpInterceptor implements Interceptor {
|
||||
logApi.setResult(response.code());
|
||||
peekBody.close();
|
||||
} catch (Exception e) {
|
||||
logApi.setRespBody(JSONUtil.createObj()
|
||||
.putOpt("code", -1)
|
||||
.putOpt("message", e.getMessage())
|
||||
.putOpt("exception", e)
|
||||
.toString());
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("code", -1);
|
||||
object.put("message", e.getMessage());
|
||||
object.put("exception", e);
|
||||
logApi.setRespBody(object.toJSONString());
|
||||
|
||||
response = new Response.Builder()
|
||||
.request(request)
|
||||
.body(OkHttpUtil.ofJsonResponse(logApi.getRespBody()))
|
||||
@@ -65,10 +66,10 @@ public class LogApiOkHttpInterceptor implements Interceptor {
|
||||
return null;
|
||||
}
|
||||
if (requestBody instanceof FormBody) {
|
||||
JSONObject jsonObject = JSONUtil.createObj();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
FormBody formBody = (FormBody) requestBody;
|
||||
for (int i = 0; i < formBody.size(); i++) {
|
||||
jsonObject.putOpt(formBody.encodedName(i), formBody.encodedValue(i));
|
||||
jsonObject.put(formBody.encodedName(i), formBody.encodedValue(i));
|
||||
}
|
||||
return jsonObject.toString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.tiesheng.web.service.imex;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.web.pojos.imex.ExportDealDTO;
|
||||
import com.tiesheng.web.pojos.imex.ImportDealDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
public class DefaultImexHandler implements TsImportHandler<String>, TsExportHandler<String> {
|
||||
|
||||
@Override
|
||||
public List<String> ready(ExportDealDTO dto, TokenBean token) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> ready(ImportDealDTO dto, TokenBean token) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateUrl() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAction() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int batchHandler(List<String> list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFailFile() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tiesheng.web.service.imex;
|
||||
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.web.pojos.imex.ExportDealDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TsExportHandler<T> extends TsImexBase<T> {
|
||||
|
||||
|
||||
/**
|
||||
* 数据准备中
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<T> ready(ExportDealDTO dto, TokenBean token);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.tiesheng.web.service.imex;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.web.util.ProcessImportConsumer;
|
||||
|
||||
public interface TsImexBase<T> extends ProcessImportConsumer<T> {
|
||||
|
||||
/**
|
||||
* 动作说明(唯一)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getAction();
|
||||
|
||||
/**
|
||||
* 排序,如果action相同,只会使用sort大的来处理
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default int getSort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否登录
|
||||
*
|
||||
* @param tokenBean
|
||||
*/
|
||||
default void validToken(TokenBean tokenBean) {
|
||||
if (tokenBean == null || StrUtil.isEmpty(tokenBean.getId())) {
|
||||
throw new ApiException("请先登录");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取模版ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default String getImexId() {
|
||||
return StrUtil.format("{}_{}", getAction(), getSort());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.tiesheng.web.service.imex;
|
||||
|
||||
import com.tiesheng.util.pojos.TokenBean;
|
||||
import com.tiesheng.web.pojos.imex.ImportDealDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TsImportHandler<T> extends TsImexBase<T> {
|
||||
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
List<T> ready(ImportDealDTO dto, TokenBean token);
|
||||
|
||||
|
||||
/**
|
||||
* 获取模版地址
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getTemplateUrl();
|
||||
|
||||
}
|
||||
@@ -6,13 +6,12 @@ public interface ProcessImportConsumer<T> {
|
||||
|
||||
|
||||
/**
|
||||
* 处理数据
|
||||
* 分批处理
|
||||
*
|
||||
* @param list
|
||||
* @param <T>
|
||||
* @return 返回成功的数量
|
||||
*/
|
||||
int accept(List<T> list);
|
||||
int batchHandler(List<T> list);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,4 +72,7 @@ CREATE TABLE `core_log_operation`
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='日志-操作';
|
||||
|
||||
|
||||
alter table core_log_process
|
||||
modify params longtext null comment '异常说明';
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<result column="type" jdbcType="VARCHAR" property="type" />
|
||||
<result column="status" jdbcType="INTEGER" property="status" />
|
||||
<result column="fail_file" jdbcType="VARCHAR" property="failFile" />
|
||||
<result column="error" jdbcType="LONGVARCHAR" property="error" />
|
||||
<result column="process" jdbcType="INTEGER" property="process" />
|
||||
<result column="params" jdbcType="LONGVARCHAR" property="params" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
|
||||
Reference in New Issue
Block a user