feat: 公共链接分享

This commit is contained in:
fit2cloud-chenyw
2021-03-26 18:44:41 +08:00
parent 89f0c5e7aa
commit ced8c21e28
27 changed files with 724 additions and 64 deletions

View File

@@ -10,8 +10,15 @@ public class RsaProperties {
public static String privateKey;
public static String publicKey;
@Value("${rsa.private_key}")
public void setPrivateKey(String privateKey) {
RsaProperties.privateKey = privateKey;
}
@Value("${rsa.public_key}")
public void setPublicKey(String publicKey) {
RsaProperties.publicKey = publicKey;
}
}

View File

@@ -118,6 +118,24 @@ public class JWTUtils {
}
}
public static String signLink(String resourceId, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
return JWT.create().withClaim("resourceId", resourceId).sign(algorithm);
}
public static boolean verifyLink(String token,String resourceId, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("resourceId", resourceId)
.build();
try {
verifier.verify(token);
return true;
}catch (Exception e){
return false;
}
}
/**
* 获取当前token上次操作时间
* @param token

View File

@@ -1,11 +1,14 @@
package io.dataease.auth.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.ArrayUtils;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RsaUtil {
@@ -23,7 +26,39 @@ public class RsaUtil {
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
// byte[] result = cipher.doFinal(Base64.decodeBase64(text));
// 下面该用分段加密
byte[] result = null;
byte[] b = Base64.decodeBase64(text);
for (int i = 0; i < b.length; i += 64) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(b, i,i + 64));
result = ArrayUtils.addAll(result, doFinal);
}
return new String(result);
}
/**
* 公钥加密
*
* @param publicKeyText 公钥
* @param text 待加密的文本
* @return /
*/
public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
/*byte[] result = cipher.doFinal(text.getBytes());*/
// 下面该用分段加密
byte[] result = null;
byte[] b = text.getBytes("utf-8");
for (int i = 0; i < b.length; i += 50) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(b, i,i + 50));
result = ArrayUtils.addAll(result, doFinal);
}
return Base64.encodeBase64String(result);
}
}

View File

@@ -7,6 +7,8 @@ import lombok.Data;
public class PanelLink implements Serializable {
private String resourceId;
private Boolean valid;
private Boolean enablePwd;
private String pwd;

View File

@@ -174,6 +174,66 @@ public class PanelLinkExample {
return (Criteria) this;
}
public Criteria andValidIsNull() {
addCriterion("`valid` is null");
return (Criteria) this;
}
public Criteria andValidIsNotNull() {
addCriterion("`valid` is not null");
return (Criteria) this;
}
public Criteria andValidEqualTo(Boolean value) {
addCriterion("`valid` =", value, "valid");
return (Criteria) this;
}
public Criteria andValidNotEqualTo(Boolean value) {
addCriterion("`valid` <>", value, "valid");
return (Criteria) this;
}
public Criteria andValidGreaterThan(Boolean value) {
addCriterion("`valid` >", value, "valid");
return (Criteria) this;
}
public Criteria andValidGreaterThanOrEqualTo(Boolean value) {
addCriterion("`valid` >=", value, "valid");
return (Criteria) this;
}
public Criteria andValidLessThan(Boolean value) {
addCriterion("`valid` <", value, "valid");
return (Criteria) this;
}
public Criteria andValidLessThanOrEqualTo(Boolean value) {
addCriterion("`valid` <=", value, "valid");
return (Criteria) this;
}
public Criteria andValidIn(List<Boolean> values) {
addCriterion("`valid` in", values, "valid");
return (Criteria) this;
}
public Criteria andValidNotIn(List<Boolean> values) {
addCriterion("`valid` not in", values, "valid");
return (Criteria) this;
}
public Criteria andValidBetween(Boolean value1, Boolean value2) {
addCriterion("`valid` between", value1, value2, "valid");
return (Criteria) this;
}
public Criteria andValidNotBetween(Boolean value1, Boolean value2) {
addCriterion("`valid` not between", value1, value2, "valid");
return (Criteria) this;
}
public Criteria andEnablePwdIsNull() {
addCriterion("enable_pwd is null");
return (Criteria) this;

View File

@@ -3,6 +3,7 @@
<mapper namespace="io.dataease.base.mapper.PanelLinkMapper">
<resultMap id="BaseResultMap" type="io.dataease.base.domain.PanelLink">
<id column="resource_id" jdbcType="VARCHAR" property="resourceId" />
<result column="valid" jdbcType="BIT" property="valid" />
<result column="enable_pwd" jdbcType="BIT" property="enablePwd" />
<result column="pwd" jdbcType="VARCHAR" property="pwd" />
</resultMap>
@@ -65,7 +66,7 @@
</where>
</sql>
<sql id="Base_Column_List">
resource_id, enable_pwd, pwd
resource_id, `valid`, enable_pwd, pwd
</sql>
<select id="selectByExample" parameterType="io.dataease.base.domain.PanelLinkExample" resultMap="BaseResultMap">
select
@@ -98,10 +99,10 @@
</if>
</delete>
<insert id="insert" parameterType="io.dataease.base.domain.PanelLink">
insert into panel_link (resource_id, enable_pwd, pwd
)
values (#{resourceId,jdbcType=VARCHAR}, #{enablePwd,jdbcType=BIT}, #{pwd,jdbcType=VARCHAR}
)
insert into panel_link (resource_id, `valid`, enable_pwd,
pwd)
values (#{resourceId,jdbcType=VARCHAR}, #{valid,jdbcType=BIT}, #{enablePwd,jdbcType=BIT},
#{pwd,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.dataease.base.domain.PanelLink">
insert into panel_link
@@ -109,6 +110,9 @@
<if test="resourceId != null">
resource_id,
</if>
<if test="valid != null">
`valid`,
</if>
<if test="enablePwd != null">
enable_pwd,
</if>
@@ -120,6 +124,9 @@
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="valid != null">
#{valid,jdbcType=BIT},
</if>
<if test="enablePwd != null">
#{enablePwd,jdbcType=BIT},
</if>
@@ -140,6 +147,9 @@
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.valid != null">
`valid` = #{record.valid,jdbcType=BIT},
</if>
<if test="record.enablePwd != null">
enable_pwd = #{record.enablePwd,jdbcType=BIT},
</if>
@@ -154,6 +164,7 @@
<update id="updateByExample" parameterType="map">
update panel_link
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
`valid` = #{record.valid,jdbcType=BIT},
enable_pwd = #{record.enablePwd,jdbcType=BIT},
pwd = #{record.pwd,jdbcType=VARCHAR}
<if test="_parameter != null">
@@ -163,6 +174,9 @@
<update id="updateByPrimaryKeySelective" parameterType="io.dataease.base.domain.PanelLink">
update panel_link
<set>
<if test="valid != null">
`valid` = #{valid,jdbcType=BIT},
</if>
<if test="enablePwd != null">
enable_pwd = #{enablePwd,jdbcType=BIT},
</if>
@@ -174,7 +188,8 @@
</update>
<update id="updateByPrimaryKey" parameterType="io.dataease.base.domain.PanelLink">
update panel_link
set enable_pwd = #{enablePwd,jdbcType=BIT},
set `valid` = #{valid,jdbcType=BIT},
enable_pwd = #{enablePwd,jdbcType=BIT},
pwd = #{pwd,jdbcType=VARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
</update>

View File

@@ -1,23 +1,44 @@
package io.dataease.controller.panel.api;
import io.dataease.controller.request.panel.link.EnablePwdRequest;
import io.dataease.controller.request.panel.link.LinkRequest;
import io.dataease.controller.request.panel.link.PasswordRequest;
import io.dataease.controller.request.panel.link.ValidateRequest;
import io.dataease.dto.panel.link.GenerateDto;
import io.dataease.dto.panel.link.ValidateDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Api(tags = "仪表板:链接管理")
@RequestMapping("/api/link")
public interface LinkApi {
@ApiOperation("设置密码")
@PostMapping("/replacePwd")
@ApiOperation("重制密码")
@PostMapping("/resetPwd")
void replacePwd(PasswordRequest request);
@ApiOperation("生成")
@PostMapping("/generate")
void generateLink(LinkRequest request);
@ApiOperation("启用密码")
@PostMapping("/enablePwd")
void enablePwd(EnablePwdRequest request);
@ApiOperation("切换开关")
@PostMapping("/switchLink")
void switchLink(LinkRequest request);
@ApiOperation("当前链接信息")
@PostMapping("/currentGenerate/{resourceId}")
GenerateDto currentGenerate(String resourceId);
@ApiOperation("验证访问")
@PostMapping("/validate")
ValidateDto validate(Map<String, String> param);
@ApiOperation("验证密码")
@PostMapping("/validatePwd")
boolean validatePwd(PasswordRequest request);
}

View File

@@ -1,22 +1,23 @@
package io.dataease.controller.panel.server;
import com.google.gson.Gson;
import io.dataease.base.domain.PanelLink;
import io.dataease.commons.utils.ServletUtils;
import io.dataease.controller.panel.api.LinkApi;
import io.dataease.controller.request.panel.link.EnablePwdRequest;
import io.dataease.controller.request.panel.link.LinkRequest;
import io.dataease.controller.request.panel.link.PasswordRequest;
import io.dataease.controller.request.panel.link.ValidateRequest;
import io.dataease.dto.panel.link.GenerateDto;
import io.dataease.dto.panel.link.ValidateDto;
import io.dataease.service.panel.PanelLinkService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
public class LinkServer implements LinkApi {
@@ -33,8 +34,47 @@ public class LinkServer implements LinkApi {
}
@Override
public void generateLink(@RequestBody LinkRequest request) {
panelLinkService.generator(request);
public void enablePwd(@RequestBody EnablePwdRequest request) {
panelLinkService.changeEnablePwd(request);
}
@Override
public void switchLink(@RequestBody LinkRequest request) {
panelLinkService.changeValid(request);
}
@Override
public GenerateDto currentGenerate(@PathVariable("resourceId") String resourceId) {
return panelLinkService.currentGenerate(resourceId);
}
@Override
public ValidateDto validate(@RequestBody Map<String, String> param) {
String link = param.get("link");
String json = null;
try {
json = panelLinkService.decryptParam(link);
} catch (Exception e) {
e.printStackTrace();
}
Gson gson = new Gson();
ValidateRequest request = gson.fromJson(json, ValidateRequest.class);
ValidateDto dto = new ValidateDto();
String resourceId = request.getResourceId();
PanelLink one = panelLinkService.findOne(resourceId);
if (ObjectUtils.isEmpty(one)){
dto.setValid(false);
return dto;
}
dto.setValid(one.getValid());
dto.setEnablePwd(one.getEnablePwd());
dto.setPassPwd(panelLinkService.validateHeads(one));
return dto;
}
@Override
public boolean validatePwd(@RequestBody PasswordRequest request) {
return panelLinkService.validatePwd(request);
}
}

View File

@@ -0,0 +1,11 @@
package io.dataease.controller.request.panel.link;
import lombok.Data;
@Data
public class EnablePwdRequest {
private String resourceId;
private boolean enablePwd;
}

View File

@@ -7,9 +7,5 @@ public class LinkRequest {
private String resourceId;
private String password;
private Boolean enablePwd;
private String uri;
private boolean valid;
}

View File

@@ -0,0 +1,15 @@
package io.dataease.controller.request.panel.link;
import lombok.Data;
@Data
public class ValidateRequest {
private String resourceId;
private Long time;
private String salt;
}

View File

@@ -0,0 +1,15 @@
package io.dataease.dto.panel.link;
import lombok.Data;
@Data
public class GenerateDto {
private boolean valid;
private boolean enablePwd;
private String uri;
private String pwd;
}

View File

@@ -0,0 +1,13 @@
package io.dataease.dto.panel.link;
import lombok.Data;
@Data
public class ValidateDto {
private boolean valid;
private boolean enablePwd;
private boolean passPwd;
}

View File

@@ -1,31 +1,51 @@
package io.dataease.service.panel;
import com.google.gson.Gson;
import io.dataease.auth.config.RsaProperties;
import io.dataease.auth.util.JWTUtils;
import io.dataease.auth.util.RsaUtil;
import io.dataease.base.domain.PanelLink;
import io.dataease.base.mapper.PanelLinkMapper;
import io.dataease.commons.constants.AuthConstants;
import io.dataease.commons.utils.ServletUtils;
import io.dataease.controller.request.panel.link.EnablePwdRequest;
import io.dataease.controller.request.panel.link.LinkRequest;
import io.dataease.controller.request.panel.link.PasswordRequest;
import io.dataease.dto.panel.link.GenerateDto;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@Service
public class PanelLinkService {
@Value("${public-link-url:http://localhost:8081/link?link=}")
private String baseUrl;
@Value("${public-link-salt:DataEaseLinkSalt}")
private String salt;
@Resource
private PanelLinkMapper mapper;
public void generator(LinkRequest request){
String resourceId = request.getResourceId();
PanelLink panelLink = mapper.selectByPrimaryKey(resourceId);
public void changeValid(LinkRequest request){
PanelLink po = new PanelLink();
po.setResourceId(resourceId);
po.setEnablePwd(request.getEnablePwd());
po.setPwd(request.getPassword());
if (ObjectUtils.isEmpty(panelLink)){
mapper.insert(po);
}else{
mapper.updateByPrimaryKey(po);
}
po.setResourceId(request.getResourceId());
po.setValid(request.isValid());
mapper.updateByPrimaryKeySelective(po);
}
public void changeEnablePwd(EnablePwdRequest request){
PanelLink po = new PanelLink();
po.setResourceId(request.getResourceId());
po.setEnablePwd(request.isEnablePwd());
mapper.updateByPrimaryKeySelective(po);
}
public void password(PasswordRequest request){
@@ -40,7 +60,80 @@ public class PanelLinkService {
return panelLink;
}
public GenerateDto currentGenerate(String resourceId) {
PanelLink one = findOne(resourceId);
if (ObjectUtils.isEmpty(one)) {
one = new PanelLink();
one.setPwd(null);
one.setResourceId(resourceId);
one.setValid(false);
one.setEnablePwd(false);
mapper.insert(one);
}
return convertDto(one);
}
public String decryptParam(String text) throws Exception {
return RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, text);
}
// 使用共钥加密
private String encrypt(String sourceValue) {
try {
return RsaUtil.encryptByPublicKey(RsaProperties.publicKey, sourceValue);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String buildLinkParam(String resourceId){
Map<String,Object> map = new HashMap<>();
map.put("resourceId", resourceId);
map.put("time", System.currentTimeMillis());
map.put("salt", salt);
Gson gson = new Gson();
String encrypt = encrypt(gson.toJson(map));
String s = null;
try {
s = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, encrypt);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(s);
return encrypt;
}
private GenerateDto convertDto(PanelLink linl){
GenerateDto result = new GenerateDto();
result.setValid(linl.getValid());
result.setEnablePwd(linl.getEnablePwd());
result.setPwd(linl.getPwd());
result.setUri(baseUrl+buildLinkParam(linl.getResourceId()));
return result;
}
// 验证请求头部携带的信息 如果正确说明通过密码验证 否则没有通过
public Boolean validateHeads(PanelLink panelLink){
HttpServletRequest request = ServletUtils.request();
String token = request.getHeader("LINK-PWD-TOKEN");
if (StringUtils.isEmpty(token)) return false;
boolean verify = JWTUtils.verifyLink(token, panelLink.getResourceId(), panelLink.getPwd());
return verify;
}
public boolean validatePwd(PasswordRequest request) {
String password = request.getPassword();
String resourceId = request.getResourceId();
PanelLink one = findOne(resourceId);
String pwd = one.getPwd();
boolean pass = StringUtils.equals(pwd, password);
if (pass){
String token = JWTUtils.signLink(resourceId, password);
HttpServletResponse httpServletResponse = ServletUtils.response();
httpServletResponse.addHeader("Access-Control-Expose-Headers", "LINK-PWD-TOKEN");
httpServletResponse.setHeader("LINK-PWD-TOKEN", token);
}
return pass;
}
}