Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
wangjiahao 2021-03-29 14:57:19 +08:00
commit c154e642c1
18 changed files with 177 additions and 74 deletions

View File

@ -39,6 +39,11 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/test/**", ANON);
filterChainDefinitionMap.put("/index.html", ANON);
filterChainDefinitionMap.put("/link.html", ANON);
//验证链接
filterChainDefinitionMap.put("/api/link/validate**", ANON);
filterChainDefinitionMap.put("/api/auth/login", ANON);
filterChainDefinitionMap.put("/unauth", ANON);
filterChainDefinitionMap.put("/display/**", ANON);

View File

@ -36,9 +36,9 @@ public interface LinkApi {
@ApiOperation("验证访问")
@PostMapping("/validate")
ValidateDto validate(Map<String, String> param);
ValidateDto validate(Map<String, String> param) throws Exception;
@ApiOperation("验证密码")
@PostMapping("/validatePwd")
boolean validatePwd(PasswordRequest request);
boolean validatePwd(PasswordRequest request) throws Exception;
}

View File

@ -49,20 +49,16 @@ public class LinkServer implements LinkApi {
}
@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 json = null;
try {
json = panelLinkService.decryptParam(link);
} catch (Exception e) {
e.printStackTrace();
}
String json = panelLinkService.decryptParam(link);
Gson gson = new Gson();
ValidateRequest request = gson.fromJson(json, ValidateRequest.class);
ValidateDto dto = new ValidateDto();
String resourceId = request.getResourceId();
PanelLink one = panelLinkService.findOne(resourceId);
dto.setResourceId(resourceId);
if (ObjectUtils.isEmpty(one)){
dto.setValid(false);
return dto;
@ -74,7 +70,7 @@ public class LinkServer implements LinkApi {
}
@Override
public boolean validatePwd(@RequestBody PasswordRequest request) {
public boolean validatePwd(@RequestBody PasswordRequest request) throws Exception {
return panelLinkService.validatePwd(request);
}
}

View File

@ -10,4 +10,6 @@ public class ValidateDto {
private boolean enablePwd;
private boolean passPwd;
private String resourceId;
}

View File

@ -25,7 +25,7 @@ import java.util.Map;
@Service
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;
@Value("${public-link-salt:DataEaseLinkSalt}")
@ -113,19 +113,19 @@ public class PanelLinkService {
}
// 验证请求头部携带的信息 如果正确说明通过密码验证 否则没有通过
public Boolean validateHeads(PanelLink panelLink){
public Boolean validateHeads(PanelLink panelLink) throws Exception{
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());
boolean verify = JWTUtils.verifyLink(token, panelLink.getResourceId(), decryptParam(panelLink.getPwd()));
return verify;
}
public boolean validatePwd(PasswordRequest request) {
String password = request.getPassword();
public boolean validatePwd(PasswordRequest request) throws Exception {
String password = decryptParam(request.getPassword());
String resourceId = request.getResourceId();
PanelLink one = findOne(resourceId);
String pwd = one.getPwd();
String pwd = decryptParam(one.getPwd());
boolean pass = StringUtils.equals(pwd, password);
if (pass){
String token = JWTUtils.signLink(resourceId, password);

View File

@ -15,7 +15,6 @@
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
},
"dependencies": {
"core-js": "^3.6.5",
"@riophae/vue-treeselect": "0.4.0",
"axios": "^0.21.1",
"echarts": "^5.0.2",
@ -31,29 +30,26 @@
"umy-ui": "^1.1.6",
"vcolorpicker": "^1.1.0",
"vue": "2.6.10",
"vue-clipboard2": "0.3.1",
"vue-codemirror": "^4.0.6",
"vue-i18n": "7.3.2",
"vue-router": "3.0.6",
"vue-uuid": "2.0.2",
"vuedraggable": "^2.24.3",
"vuex": "3.1.0",
"vue-clipboard2": "0.3.1",
"webpack": "^4.46.0"
},
"devDependencies": {
"@babel/core": "^7.4.0-0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "10.1.0",
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-service": "3.6.0",
"babel-eslint": "10.0.1",
"chalk": "2.4.2",
"connect": "3.6.6",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"eslint-plugin-import": "^2.20.2",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",
"html-webpack-plugin": "3.2.0",
"less": "^4.1.1",
"less-loader": "^8.0.0",

View File

@ -5,6 +5,7 @@ export function validate(data) {
url: 'api/link/validate',
method: 'post',
loading: true,
hideMsg: true,
data
})
}

View File

@ -1,6 +1,7 @@
import Vue from 'vue'
import Link from './Link.vue'
import router from './link-router'
import store from '../store'
import '@/styles/index.scss' // global css
import i18n from '../lang' // internationalization
import ElementUI from 'element-ui'
@ -11,5 +12,6 @@ Vue.use(ElementUI, {
})
new Vue({
router,
store,
render: h => h(Link)
}).$mount('#link')

View File

@ -17,7 +17,6 @@ const getters = {
table: state => state.dataset.table,
loadingMap: state => state.request.loadingMap,
currentPath: state => state.permission.currentPath,
permissions: state => state.user.permissions,
linkToken: state => state.link.linkToken
permissions: state => state.user.permissions
}
export default getters

View File

@ -9,7 +9,6 @@ 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,8 +111,7 @@ const data = {
dataset,
chart,
request,
panel,
link
panel
},
getters
}

View File

@ -1,24 +0,0 @@
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
}

View File

@ -3,6 +3,8 @@ import Config from '@/settings'
const TokenKey = Config.TokenKey
const linkTokenKey = Config.LinkTokenKey
export function getToken() {
return Cookies.get(TokenKey)
}
@ -15,3 +17,15 @@ export function removeToken() {
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)
}

View File

@ -6,6 +6,7 @@ import { getToken } from '@/utils/auth'
import Config from '@/settings'
import i18n from '@/lang'
import { tryShowLoading, tryHideLoading } from './loading'
import { getLinkToken, setLinkToken } from '@/utils/auth'
// import router from '@/router'
const TokenKey = Config.TokenKey
@ -29,8 +30,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
let linkToken = null
if ((linkToken = getLinkToken()) !== null) {
config.headers[LinkTokenKey] = linkToken
}
// 增加loading
@ -73,9 +75,9 @@ const checkAuth = response => {
store.dispatch('user/refreshToken', refreshToken)
}
if (response.headers[LinkTokenKey]) {
const linkToken = response.headers[LinkTokenKey]
store.dispatch('link/setLinkToken', linkToken)
if (response.headers[LinkTokenKey.toLocaleLowerCase()]) {
const linkToken = response.headers[LinkTokenKey.toLocaleLowerCase()]
setLinkToken(linkToken)
}
}
@ -147,7 +149,7 @@ service.interceptors.response.use(response => {
console.log('error: ' + error) // for debug
msg = error.message
}
$error(msg)
!error.config.hideMsg && $error(msg)
return Promise.reject(error)
})
export default service

View File

@ -1,6 +1,37 @@
<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>
</template>
@ -9,11 +40,81 @@ export default {
name: 'LinkError',
data() {
return {
size: 200,
stroke: 30,
percentage: 100,
timer: null,
seconds: 5
}
},
methods: {
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: {
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>
<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>

View File

@ -1,8 +1,8 @@
<template>
<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-view v-if="showIndex===2" />
<link-view v-if="showIndex===2" :resource-id="resourceId" />
</div>
</template>
<script>
@ -17,6 +17,7 @@ export default {
},
data() {
return {
resourceId: null,
PARAMKEY: 'link',
link: null,
showIndex: -1
@ -30,9 +31,10 @@ export default {
loadInit() {
this.link = getQueryVariable(this.PARAMKEY)
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()
return
}
@ -43,6 +45,8 @@ export default {
}
this.showView()
}).catch(() => {
this.showError()
})
},

View File

@ -22,7 +22,7 @@
<div class="auth-root-class">
<span slot="footer">
<el-button size="mini" type="primary" @click="validatePwd">确定</el-button>
<el-button size="mini" type="primary" @click="refresh">确定</el-button>
</span>
</div>
</div>
@ -33,6 +33,8 @@
<script>
import { validatePwd } from '@/api/link'
import { encrypt } from '@/utils/rsaEncrypt'
export default {
name: 'LinkPwd',
props: {
@ -47,10 +49,15 @@ export default {
msg: null
}
},
methods: {
// LINK-PWD-TOKEN=entrypt(pwd)
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) {
this.msg = '密码错误'
} else {

View File

@ -1,6 +1,6 @@
<template>
<div>
我是视图7u页面
我是视图页面
</div>
</template>

View File

@ -132,7 +132,7 @@
<el-dialog
:title="linkTitle"
:visible.sync="linkVisible"
custom-class="de-dialog"
width="500px"
@closed="removeLink"
>
<link-generate v-if="linkVisible" :resource-id="linkResourceId" />