feat: 公共链接分享
This commit is contained in:
parent
89f0c5e7aa
commit
ced8c21e28
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@ import lombok.Data;
|
||||
public class PanelLink implements Serializable {
|
||||
private String resourceId;
|
||||
|
||||
private Boolean valid;
|
||||
|
||||
private Boolean enablePwd;
|
||||
|
||||
private String pwd;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
package io.dataease.controller.request.panel.link;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EnablePwdRequest {
|
||||
|
||||
private String resourceId;
|
||||
|
||||
private boolean enablePwd;
|
||||
}
|
||||
@ -7,9 +7,5 @@ public class LinkRequest {
|
||||
|
||||
private String resourceId;
|
||||
|
||||
private String password;
|
||||
|
||||
private Boolean enablePwd;
|
||||
|
||||
private String uri;
|
||||
private boolean valid;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ management.endpoints.web.exposure.include=*
|
||||
#spring.freemarker.checkTemplateLocation=false
|
||||
#RSA非对称加密参数:私钥
|
||||
rsa.private_key=MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
|
||||
rsa.public_key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==
|
||||
spring.cache.type=ehcache
|
||||
spring.cache.ehcache.config=classpath:/ehcache/ehcache.xml
|
||||
#打印URL路径
|
||||
@ -60,7 +61,6 @@ logging.level.org.springframework.boot.web=trace
|
||||
spring.mvc.log-request-details=true
|
||||
pagehelper.PageRowBounds=true
|
||||
|
||||
front-url=http://localhost:9528
|
||||
|
||||
|
||||
|
||||
|
||||
@ -139,6 +139,7 @@ SET FOREIGN_KEY_CHECKS = 1;
|
||||
DROP TABLE IF EXISTS `panel_link`;
|
||||
CREATE TABLE `panel_link` (
|
||||
`resource_id` varchar(50) NOT NULL COMMENT '资源ID',
|
||||
`valid` tinyint(1) default 0 COMMENT '启用链接',
|
||||
`enable_pwd` tinyint(1) default 0 COMMENT '启用密码',
|
||||
`pwd` varchar(255) DEFAULT NULL COMMENT '密码',
|
||||
PRIMARY KEY (`resource_id`)
|
||||
|
||||
@ -1,18 +1,49 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function validate(param) {
|
||||
export function validate(data) {
|
||||
return request({
|
||||
url: 'api/link/validate',
|
||||
method: 'post',
|
||||
loading: true,
|
||||
param
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function generate(param) {
|
||||
export function validatePwd(data) {
|
||||
return request({
|
||||
url: 'api/link/generate',
|
||||
url: 'api/link/validatePwd',
|
||||
method: 'post',
|
||||
param
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function setPwd(data) {
|
||||
return request({
|
||||
url: 'api/link/resetPwd',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function switchValid(data) {
|
||||
return request({
|
||||
url: 'api/link/switchLink',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function switchEnablePwd(data) {
|
||||
return request({
|
||||
url: 'api/link/enablePwd',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function loadGenerate(resourceId) {
|
||||
return request({
|
||||
url: 'api/link/currentGenerate/' + resourceId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import Vue from 'vue'
|
||||
import Link from './Link.vue'
|
||||
import router from './link-router'
|
||||
import '@/styles/index.scss' // global css
|
||||
import i18n from '../lang' // internationalization
|
||||
import ElementUI from 'element-ui'
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(ElementUI, {
|
||||
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(Link)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
module.exports = {
|
||||
TokenKey: 'Authorization',
|
||||
RefreshTokenKey: 'refreshauthorization',
|
||||
LinkTokenKey: 'LINK-PWD-TOKEN',
|
||||
title: 'DATA_EASE',
|
||||
|
||||
/**
|
||||
|
||||
@ -17,6 +17,7 @@ const getters = {
|
||||
table: state => state.dataset.table,
|
||||
loadingMap: state => state.request.loadingMap,
|
||||
currentPath: state => state.permission.currentPath,
|
||||
permissions: state => state.user.permissions
|
||||
permissions: state => state.user.permissions,
|
||||
linkToken: state => state.link.linkToken
|
||||
}
|
||||
export default getters
|
||||
|
||||
@ -9,7 +9,7 @@ import dataset from './modules/dataset'
|
||||
import chart from './modules/chart'
|
||||
import request from './modules/request'
|
||||
import panel from './modules/panel'
|
||||
|
||||
import link from './modules/link'
|
||||
import animation from './animation'
|
||||
import compose from './compose'
|
||||
import contextmenu from './contextmenu'
|
||||
@ -112,7 +112,8 @@ const data = {
|
||||
dataset,
|
||||
chart,
|
||||
request,
|
||||
panel
|
||||
panel,
|
||||
link
|
||||
},
|
||||
getters
|
||||
}
|
||||
|
||||
24
frontend/src/store/modules/link.js
Normal file
24
frontend/src/store/modules/link.js
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
const state = {
|
||||
linkToken: null
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_LINK_TOKEN: (state, value) => {
|
||||
state.linkToken = value
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
setLinkToken({ commit }, data) {
|
||||
commit('SET_LINK_TOKEN', data)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
|
||||
@ -122,3 +122,11 @@ div:focus {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.real-input {
|
||||
|
||||
.el-input__inner {
|
||||
height: 25px !important;
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { tryShowLoading, tryHideLoading } from './loading'
|
||||
|
||||
const TokenKey = Config.TokenKey
|
||||
const RefreshTokenKey = Config.RefreshTokenKey
|
||||
const LinkTokenKey = Config.LinkTokenKey
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||
@ -28,6 +29,9 @@ service.interceptors.request.use(
|
||||
// please modify it according to the actual situation
|
||||
config.headers[TokenKey] = getToken()
|
||||
}
|
||||
if (store.getters.linkToken) {
|
||||
config.headers[LinkTokenKey] = store.getters.linkToken
|
||||
}
|
||||
// 增加loading
|
||||
|
||||
config.loading && tryShowLoading(store.getters.currentPath)
|
||||
@ -68,6 +72,11 @@ const checkAuth = response => {
|
||||
const refreshToken = response.headers[RefreshTokenKey]
|
||||
store.dispatch('user/refreshToken', refreshToken)
|
||||
}
|
||||
|
||||
if (response.headers[LinkTokenKey]) {
|
||||
const linkToken = response.headers[LinkTokenKey]
|
||||
store.dispatch('link/setLinkToken', linkToken)
|
||||
}
|
||||
}
|
||||
|
||||
const checkPermission = response => {
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
style="width: 370px;"
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
@change="onChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
@ -22,10 +23,10 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="valid" label=" ">
|
||||
<el-checkbox v-model="form.enablePwd">密码保护</el-checkbox>
|
||||
<el-checkbox v-model="form.enablePwd" @change="resetEnablePwd">密码保护</el-checkbox>
|
||||
|
||||
<span v-if="form.enablePwd" class="de-span">{{ form.pwd }}</span>
|
||||
<span v-if="form.enablePwd" class="de-span"><el-link :underline="false" type="primary">重置</el-link></span>
|
||||
<span v-if="form.enablePwd" class="de-span" @click="resetPwd"><el-link :underline="false" type="primary">重置</el-link></span>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="valid" class="auth-root-class">
|
||||
@ -41,6 +42,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import { loadGenerate, setPwd, switchValid, switchEnablePwd } from '@/api/link'
|
||||
import { encrypt, decrypt } from '@/utils/rsaEncrypt'
|
||||
|
||||
export default {
|
||||
|
||||
name: 'LinkGenerate',
|
||||
@ -55,20 +60,75 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pwdNums: 4,
|
||||
valid: false,
|
||||
form: {},
|
||||
defaultForm: { enablePwd: false, pwd: '000000', uri: 'http://baidu.com' }
|
||||
defaultForm: { enablePwd: false, pwd: null, uri: null }
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.defaultForm
|
||||
this.currentGenerate()
|
||||
},
|
||||
methods: {
|
||||
currentGenerate() {
|
||||
loadGenerate(this.resourceId).then(res => {
|
||||
const { valid, enablePwd, pwd, uri } = res.data
|
||||
this.valid = valid
|
||||
this.form.enablePwd = enablePwd
|
||||
this.form.uri = uri
|
||||
// 返回的密码是共钥加密后的 所以展示需要私钥解密一波
|
||||
pwd && (this.form.pwd = decrypt(pwd))
|
||||
})
|
||||
},
|
||||
|
||||
createPwd() {
|
||||
const randomNum = () => {
|
||||
return Math.floor(Math.random() * 10) + ''
|
||||
}
|
||||
let result = ''
|
||||
for (let index = 0; index < this.pwdNums; index++) {
|
||||
result += randomNum()
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
resetPwd() {
|
||||
// 密码采用RSA共钥加密
|
||||
const newPwd = this.createPwd()
|
||||
const param = {
|
||||
resourceId: this.resourceId,
|
||||
password: encrypt(newPwd)
|
||||
}
|
||||
setPwd(param).then(res => {
|
||||
this.form.pwd = newPwd
|
||||
})
|
||||
},
|
||||
resetEnablePwd(value) {
|
||||
const param = {
|
||||
resourceId: this.resourceId,
|
||||
enablePwd: value
|
||||
}
|
||||
switchEnablePwd(param).then(res => {
|
||||
// 当切换到启用密码保护 如果没有密码 要生成密码
|
||||
value && !this.form.pwd && this.resetPwd()
|
||||
})
|
||||
},
|
||||
|
||||
onCopy(e) {
|
||||
// alert('You just copied: ' + e.text)
|
||||
},
|
||||
onError(e) {
|
||||
// alert('Failed to copy texts')
|
||||
},
|
||||
onChange(value) {
|
||||
const param = {
|
||||
resourceId: this.resourceId,
|
||||
valid: value
|
||||
}
|
||||
switchValid(param).then(res => {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<link-error v-if="showIndex===0" />
|
||||
<link-pwd v-if="showIndex===1" />
|
||||
<link-pwd v-if="showIndex===1" :resource-id="resourceId" />
|
||||
<link-view v-if="showIndex===2" />
|
||||
</div>
|
||||
</template>
|
||||
@ -29,24 +29,23 @@ export default {
|
||||
|
||||
loadInit() {
|
||||
this.link = getQueryVariable(this.PARAMKEY)
|
||||
validate(this.buildParam()).then(res => {
|
||||
validate({ link: this.link }).then(res => {
|
||||
const { valid, enablePwd, passPwd } = res.data
|
||||
// 如果链接无效 直接显示无效页面
|
||||
!valid && this.showError()
|
||||
if (!valid) {
|
||||
this.showError()
|
||||
return
|
||||
}
|
||||
|
||||
// 如果未启用密码 直接显示视图页面
|
||||
!enablePwd && this.showView()
|
||||
|
||||
// 如果启用密码 但是未通过密码验证 显示密码框
|
||||
!passPwd && this.showPwd()
|
||||
if (enablePwd && !passPwd) {
|
||||
this.showPwd()
|
||||
return
|
||||
}
|
||||
|
||||
this.showView()
|
||||
})
|
||||
console.log(this.link)
|
||||
},
|
||||
buildParam() {
|
||||
return {}
|
||||
},
|
||||
|
||||
// 显示无效链接
|
||||
showError() {
|
||||
this.showIndex = 0
|
||||
|
||||
@ -1,19 +1,196 @@
|
||||
<template>
|
||||
<div>
|
||||
我是密码页面
|
||||
<div class="pwd-body">
|
||||
<div class="pwd-wrapper">
|
||||
<div class="pwd-content">
|
||||
|
||||
<div class="span-header">
|
||||
<div class="bi-text">
|
||||
请输入密码打开链接
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-layout">
|
||||
<div class="input-main">
|
||||
<div class="div-input">
|
||||
<el-input v-model="pwd" class="real-input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="abs-input">
|
||||
<div class="input-text">{{ msg }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-root-class">
|
||||
<span slot="footer">
|
||||
<el-button size="mini" type="primary" @click="validatePwd">确定</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validatePwd } from '@/api/link'
|
||||
export default {
|
||||
name: 'LinkPwd',
|
||||
props: {
|
||||
resourceId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
pwd: null,
|
||||
msg: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 验证密码是否正确 如果正确 设置请求头部带LINK-PWD-TOKEN=entrypt(pwd)再刷新页面
|
||||
refresh() {
|
||||
validatePwd({ password: this.pwd, resourceId: this.resourceId }).then(res => {
|
||||
if (!res.data) {
|
||||
this.msg = '密码错误'
|
||||
} else {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pwd-body {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-repeat: repeat;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
color: #3d4d66;
|
||||
font: normal 12px Helvetica Neue,Arial,PingFang SC,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Heiti,黑体,sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-decoration: none;
|
||||
-kthml-user-focus: normal;
|
||||
-moz-user-focus: normal;
|
||||
-moz-outline: 0 none;
|
||||
outline: 0 none;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
.pwd-wrapper {
|
||||
background-color: #F7F8FA;
|
||||
height: 100%;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
min-height: 25px;
|
||||
display: flex;
|
||||
-moz-flex-direction: row;
|
||||
-o-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-moz-justify-content: flex-start;
|
||||
-ms-justify-content: flex-start;
|
||||
-o-justify-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
-moz-align-items: flex-start;
|
||||
-ms-align-items: flex-start;
|
||||
-o-align-items: flex-start;
|
||||
align-items: flex-start;
|
||||
-o-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.pwd-content {
|
||||
width: 450px;
|
||||
height: 250px;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
background-color: #FFFFFF;
|
||||
display: block;
|
||||
}
|
||||
.span-header {
|
||||
position: relative;
|
||||
margin: 57px auto 0px;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
.bi-text {
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
word-break: break-all;
|
||||
display: block;
|
||||
}
|
||||
.input-layout{
|
||||
width: 152px;
|
||||
position: relative;
|
||||
margin: 0px auto;
|
||||
padding: 0;
|
||||
display: block;
|
||||
}
|
||||
.input-main {
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
border: 1px solid #e8eaed;
|
||||
display: block;
|
||||
}
|
||||
.div-input {
|
||||
inset: 2px 4px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
}
|
||||
.abs-input {
|
||||
height: 20px;
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
display: block;
|
||||
}
|
||||
.input-text {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
position: absolute;
|
||||
color: #E65251;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.real-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
inset: 0px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
|
||||
}
|
||||
.auth-root-class {
|
||||
margin: 15px 0px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user