提交 12a22664 authored 作者: fit2cloud-chenyw's avatar fit2cloud-chenyw

feat: 完善公共链接分享

上级 2f3af28b
...@@ -39,6 +39,11 @@ public class ShiroServiceImpl implements ShiroService { ...@@ -39,6 +39,11 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/test/**", ANON); filterChainDefinitionMap.put("/test/**", ANON);
filterChainDefinitionMap.put("/index.html", ANON); filterChainDefinitionMap.put("/index.html", ANON);
filterChainDefinitionMap.put("/link.html", ANON); filterChainDefinitionMap.put("/link.html", ANON);
//验证链接
filterChainDefinitionMap.put("/api/link/validate**", ANON);
filterChainDefinitionMap.put("/api/auth/login", ANON); filterChainDefinitionMap.put("/api/auth/login", ANON);
filterChainDefinitionMap.put("/unauth", ANON); filterChainDefinitionMap.put("/unauth", ANON);
filterChainDefinitionMap.put("/display/**", ANON); filterChainDefinitionMap.put("/display/**", ANON);
......
...@@ -36,9 +36,9 @@ public interface LinkApi { ...@@ -36,9 +36,9 @@ public interface LinkApi {
@ApiOperation("验证访问") @ApiOperation("验证访问")
@PostMapping("/validate") @PostMapping("/validate")
ValidateDto validate(Map<String, String> param); ValidateDto validate(Map<String, String> param) throws Exception;
@ApiOperation("验证密码") @ApiOperation("验证密码")
@PostMapping("/validatePwd") @PostMapping("/validatePwd")
boolean validatePwd(PasswordRequest request); boolean validatePwd(PasswordRequest request) throws Exception;
} }
...@@ -49,20 +49,16 @@ public class LinkServer implements LinkApi { ...@@ -49,20 +49,16 @@ public class LinkServer implements LinkApi {
} }
@Override @Override
public ValidateDto validate(@RequestBody Map<String, String> param) { public ValidateDto validate(@RequestBody Map<String, String> param) throws Exception{
String link = param.get("link"); String link = param.get("link");
String json = null; String json = panelLinkService.decryptParam(link);
try {
json = panelLinkService.decryptParam(link);
} catch (Exception e) {
e.printStackTrace();
}
Gson gson = new Gson(); Gson gson = new Gson();
ValidateRequest request = gson.fromJson(json, ValidateRequest.class); ValidateRequest request = gson.fromJson(json, ValidateRequest.class);
ValidateDto dto = new ValidateDto(); ValidateDto dto = new ValidateDto();
String resourceId = request.getResourceId(); String resourceId = request.getResourceId();
PanelLink one = panelLinkService.findOne(resourceId); PanelLink one = panelLinkService.findOne(resourceId);
dto.setResourceId(resourceId);
if (ObjectUtils.isEmpty(one)){ if (ObjectUtils.isEmpty(one)){
dto.setValid(false); dto.setValid(false);
return dto; return dto;
...@@ -74,7 +70,7 @@ public class LinkServer implements LinkApi { ...@@ -74,7 +70,7 @@ public class LinkServer implements LinkApi {
} }
@Override @Override
public boolean validatePwd(@RequestBody PasswordRequest request) { public boolean validatePwd(@RequestBody PasswordRequest request) throws Exception {
return panelLinkService.validatePwd(request); return panelLinkService.validatePwd(request);
} }
} }
...@@ -10,4 +10,6 @@ public class ValidateDto { ...@@ -10,4 +10,6 @@ public class ValidateDto {
private boolean enablePwd; private boolean enablePwd;
private boolean passPwd; private boolean passPwd;
private String resourceId;
} }
...@@ -25,7 +25,7 @@ import java.util.Map; ...@@ -25,7 +25,7 @@ import java.util.Map;
@Service @Service
public class PanelLinkService { public class PanelLinkService {
@Value("${public-link-url:http://localhost:8081/link?link=}") @Value("${public-link-url:http://localhost:9528/link.html?link=}")
private String baseUrl; private String baseUrl;
@Value("${public-link-salt:DataEaseLinkSalt}") @Value("${public-link-salt:DataEaseLinkSalt}")
...@@ -113,19 +113,19 @@ public class PanelLinkService { ...@@ -113,19 +113,19 @@ public class PanelLinkService {
} }
// 验证请求头部携带的信息 如果正确说明通过密码验证 否则没有通过 // 验证请求头部携带的信息 如果正确说明通过密码验证 否则没有通过
public Boolean validateHeads(PanelLink panelLink){ public Boolean validateHeads(PanelLink panelLink) throws Exception{
HttpServletRequest request = ServletUtils.request(); HttpServletRequest request = ServletUtils.request();
String token = request.getHeader("LINK-PWD-TOKEN"); String token = request.getHeader("LINK-PWD-TOKEN");
if (StringUtils.isEmpty(token)) return false; if (StringUtils.isEmpty(token)) return false;
boolean verify = JWTUtils.verifyLink(token, panelLink.getResourceId(), panelLink.getPwd()); boolean verify = JWTUtils.verifyLink(token, panelLink.getResourceId(), decryptParam(panelLink.getPwd()));
return verify; return verify;
} }
public boolean validatePwd(PasswordRequest request) { public boolean validatePwd(PasswordRequest request) throws Exception {
String password = request.getPassword(); String password = decryptParam(request.getPassword());
String resourceId = request.getResourceId(); String resourceId = request.getResourceId();
PanelLink one = findOne(resourceId); PanelLink one = findOne(resourceId);
String pwd = one.getPwd(); String pwd = decryptParam(one.getPwd());
boolean pass = StringUtils.equals(pwd, password); boolean pass = StringUtils.equals(pwd, password);
if (pass){ if (pass){
String token = JWTUtils.signLink(resourceId, password); String token = JWTUtils.signLink(resourceId, password);
......
...@@ -5,6 +5,7 @@ export function validate(data) { ...@@ -5,6 +5,7 @@ export function validate(data) {
url: 'api/link/validate', url: 'api/link/validate',
method: 'post', method: 'post',
loading: true, loading: true,
hideMsg: true,
data data
}) })
} }
......
import Vue from 'vue' import Vue from 'vue'
import Link from './Link.vue' import Link from './Link.vue'
import router from './link-router' import router from './link-router'
import store from '../store'
import '@/styles/index.scss' // global css import '@/styles/index.scss' // global css
import i18n from '../lang' // internationalization import i18n from '../lang' // internationalization
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
...@@ -11,5 +12,6 @@ Vue.use(ElementUI, { ...@@ -11,5 +12,6 @@ Vue.use(ElementUI, {
}) })
new Vue({ new Vue({
router, router,
store,
render: h => h(Link) render: h => h(Link)
}).$mount('#link') }).$mount('#link')
...@@ -17,7 +17,6 @@ const getters = { ...@@ -17,7 +17,6 @@ const getters = {
table: state => state.dataset.table, table: state => state.dataset.table,
loadingMap: state => state.request.loadingMap, loadingMap: state => state.request.loadingMap,
currentPath: state => state.permission.currentPath, currentPath: state => state.permission.currentPath,
permissions: state => state.user.permissions, permissions: state => state.user.permissions
linkToken: state => state.link.linkToken
} }
export default getters export default getters
...@@ -9,7 +9,6 @@ import dataset from './modules/dataset' ...@@ -9,7 +9,6 @@ import dataset from './modules/dataset'
import chart from './modules/chart' import chart from './modules/chart'
import request from './modules/request' import request from './modules/request'
import panel from './modules/panel' import panel from './modules/panel'
import link from './modules/link'
import animation from './animation' import animation from './animation'
import compose from './compose' import compose from './compose'
import contextmenu from './contextmenu' import contextmenu from './contextmenu'
...@@ -112,8 +111,7 @@ const data = { ...@@ -112,8 +111,7 @@ const data = {
dataset, dataset,
chart, chart,
request, request,
panel, panel
link
}, },
getters getters
} }
......
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
}
...@@ -3,6 +3,8 @@ import Config from '@/settings' ...@@ -3,6 +3,8 @@ import Config from '@/settings'
const TokenKey = Config.TokenKey const TokenKey = Config.TokenKey
const linkTokenKey = Config.LinkTokenKey
export function getToken() { export function getToken() {
return Cookies.get(TokenKey) return Cookies.get(TokenKey)
} }
...@@ -15,3 +17,15 @@ export function removeToken() { ...@@ -15,3 +17,15 @@ export function removeToken() {
return Cookies.remove(TokenKey) return Cookies.remove(TokenKey)
} }
export function getLinkToken() {
return Cookies.get(linkTokenKey)
}
export function setLinkToken(token) {
return Cookies.set(linkTokenKey, token)
}
export function removeLinkToken() {
return Cookies.remove(linkTokenKey)
}
...@@ -6,6 +6,7 @@ import { getToken } from '@/utils/auth' ...@@ -6,6 +6,7 @@ import { getToken } from '@/utils/auth'
import Config from '@/settings' import Config from '@/settings'
import i18n from '@/lang' import i18n from '@/lang'
import { tryShowLoading, tryHideLoading } from './loading' import { tryShowLoading, tryHideLoading } from './loading'
import { getLinkToken, setLinkToken } from '@/utils/auth'
// import router from '@/router' // import router from '@/router'
const TokenKey = Config.TokenKey const TokenKey = Config.TokenKey
...@@ -29,8 +30,9 @@ service.interceptors.request.use( ...@@ -29,8 +30,9 @@ service.interceptors.request.use(
// please modify it according to the actual situation // please modify it according to the actual situation
config.headers[TokenKey] = getToken() config.headers[TokenKey] = getToken()
} }
if (store.getters.linkToken) { let linkToken = null
config.headers[LinkTokenKey] = store.getters.linkToken if ((linkToken = getLinkToken()) !== null) {
config.headers[LinkTokenKey] = linkToken
} }
// 增加loading // 增加loading
...@@ -73,9 +75,9 @@ const checkAuth = response => { ...@@ -73,9 +75,9 @@ const checkAuth = response => {
store.dispatch('user/refreshToken', refreshToken) store.dispatch('user/refreshToken', refreshToken)
} }
if (response.headers[LinkTokenKey]) { if (response.headers[LinkTokenKey.toLocaleLowerCase()]) {
const linkToken = response.headers[LinkTokenKey] const linkToken = response.headers[LinkTokenKey.toLocaleLowerCase()]
store.dispatch('link/setLinkToken', linkToken) setLinkToken(linkToken)
} }
} }
...@@ -147,7 +149,7 @@ service.interceptors.response.use(response => { ...@@ -147,7 +149,7 @@ service.interceptors.response.use(response => {
console.log('error: ' + error) // for debug console.log('error: ' + error) // for debug
msg = error.message msg = error.message
} }
$error(msg) !error.config.hideMsg && $error(msg)
return Promise.reject(error) return Promise.reject(error)
}) })
export default service export default service
<template> <template>
<div> <div class="pwd-body">
我是错误页面
<div class="countdown">
<svg
:width="size"
:height="size"
>
<circle
fill="transparent"
:stroke-width="stroke"
stroke="#270B58"
:r="radius"
:cx="circleOffset"
:cy="circleOffset"
/>
<circle
class="circle"
fill="transparent"
:stroke-width="stroke"
stroke="#F36F21"
:r="radius"
:cx="circleOffset"
:cy="circleOffset"
:stroke-dasharray="circumference"
:stroke-dashoffset="progress"
stroke-linecap="round"
/>
</svg>
<span>{{ countdown }}</span>
</div>
<div>
<h1>链接无效 即将跳转登录页面</h1>
</div>
</div> </div>
</template> </template>
...@@ -9,11 +40,81 @@ export default { ...@@ -9,11 +40,81 @@ export default {
name: 'LinkError', name: 'LinkError',
data() { data() {
return { return {
size: 200,
stroke: 30,
percentage: 100,
timer: null,
seconds: 5
}
},
computed: {
radius() {
return (this.size / 2) - (this.stroke / 2)
},
circleOffset() {
return this.size / 2
},
circumference() {
return this.radius * 2 * Math.PI
},
progress() {
return this.circumference - this.circumference * this.percentage / 100
},
countdown() {
return Math.ceil(this.seconds * this.percentage / 100)
} }
},
mounted() {
this.$nextTick(() => {
this.animate()
})
}, },
methods: { methods: {
animate() {
this.timer = setInterval(() => {
this.percentage -= 1 / 10
if (this.percentage <= 0) {
clearInterval(this.timer)
this.percentage = 100
this.$store.dispatch('user/logout')
window.location.href = '/login'
}
}, this.seconds * 1000 / 100 / 10)
}
} }
} }
</script> </script>
<style scoped>
.circle {
transform: rotate(-90deg);
transform-origin: 50% 50%;;
}
.countdown {
display: inline-block;
position: relative;
margin-top: 15%;
}
span {
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
font-size: 180px;
font-family: monospace;
color: #F36F21;
}
.pwd-body {
display: block;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
background-color: #F7F8FA;
}
</style>
<template> <template>
<div> <div>
<link-error v-if="showIndex===0" /> <link-error v-if="showIndex===0" :resource-id="resourceId" />
<link-pwd v-if="showIndex===1" :resource-id="resourceId" /> <link-pwd v-if="showIndex===1" :resource-id="resourceId" />
<link-view v-if="showIndex===2" /> <link-view v-if="showIndex===2" :resource-id="resourceId" />
</div> </div>
</template> </template>
<script> <script>
...@@ -17,6 +17,7 @@ export default { ...@@ -17,6 +17,7 @@ export default {
}, },
data() { data() {
return { return {
resourceId: null,
PARAMKEY: 'link', PARAMKEY: 'link',
link: null, link: null,
showIndex: -1 showIndex: -1
...@@ -30,9 +31,10 @@ export default { ...@@ -30,9 +31,10 @@ export default {
loadInit() { loadInit() {
this.link = getQueryVariable(this.PARAMKEY) this.link = getQueryVariable(this.PARAMKEY)
validate({ link: this.link }).then(res => { validate({ link: this.link }).then(res => {
const { valid, enablePwd, passPwd } = res.data const { resourceId, valid, enablePwd, passPwd } = res.data
this.resourceId = resourceId
// 如果链接无效 直接显示无效页面 // 如果链接无效 直接显示无效页面
if (!valid) { if (!valid || !resourceId) {
this.showError() this.showError()
return return
} }
...@@ -43,6 +45,8 @@ export default { ...@@ -43,6 +45,8 @@ export default {
} }
this.showView() this.showView()
}).catch(() => {
this.showError()
}) })
}, },
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<div class="auth-root-class"> <div class="auth-root-class">
<span slot="footer"> <span slot="footer">
<el-button size="mini" type="primary" @click="validatePwd">确定</el-button> <el-button size="mini" type="primary" @click="refresh">确定</el-button>
</span> </span>
</div> </div>
</div> </div>
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
<script> <script>
import { validatePwd } from '@/api/link' import { validatePwd } from '@/api/link'
import { encrypt } from '@/utils/rsaEncrypt'
export default { export default {
name: 'LinkPwd', name: 'LinkPwd',
props: { props: {
...@@ -47,10 +49,15 @@ export default { ...@@ -47,10 +49,15 @@ export default {
msg: null msg: null
} }
}, },
methods: { methods: {
// 验证密码是否正确 如果正确 设置请求头部带LINK-PWD-TOKEN=entrypt(pwd)再刷新页面 // 验证密码是否正确 如果正确 设置请求头部带LINK-PWD-TOKEN=entrypt(pwd)再刷新页面
refresh() { refresh() {
validatePwd({ password: this.pwd, resourceId: this.resourceId }).then(res => { const param = {
password: encrypt(this.pwd),
resourceId: this.resourceId
}
validatePwd(param).then(res => {
if (!res.data) { if (!res.data) {
this.msg = '密码错误' this.msg = '密码错误'
} else { } else {
......
<template> <template>
<div> <div>
我是视图7u页面 我是视图页面
</div> </div>
</template> </template>
......
...@@ -132,7 +132,7 @@ ...@@ -132,7 +132,7 @@
<el-dialog <el-dialog
:title="linkTitle" :title="linkTitle"
:visible.sync="linkVisible" :visible.sync="linkVisible"
custom-class="de-dialog" width="500px"
@closed="removeLink" @closed="removeLink"
> >
<link-generate v-if="linkVisible" :resource-id="linkResourceId" /> <link-generate v-if="linkVisible" :resource-id="linkResourceId" />
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论