mirror of
https://github.com/dataease/dataease.git
synced 2025-02-24 19:42:56 +08:00
Merge pull request #4566 from dataease/pr@dev@feat_dingtalk_mobile
feat(登录): 移动端钉钉工作台免登进入DE
This commit is contained in:
commit
55473304d0
@ -84,7 +84,7 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
token = (String) auth.getCredentials();
|
||||
// 解密获得username,用于和数据库进行对比
|
||||
tokenInfo = JWTUtils.tokenInfoByToken(token);
|
||||
if (!TokenCacheUtils.validate(token)) {
|
||||
if (TokenCacheUtils.invalid(token)) {
|
||||
throw new AuthenticationException("token invalid");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -66,7 +66,7 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
if (StringUtils.startsWith(authorization, "Basic")) {
|
||||
return false;
|
||||
}
|
||||
if (!TokenCacheUtils.validate(authorization) && !TokenCacheUtils.validateDelay(authorization)) {
|
||||
if (TokenCacheUtils.invalid(authorization)) {
|
||||
throw new AuthenticationException(expireMessage);
|
||||
}
|
||||
// 当没有出现登录超时 且需要刷新token 则执行刷新token
|
||||
@ -75,8 +75,6 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
throw new AuthenticationException(expireMessage);
|
||||
}
|
||||
if (JWTUtils.needRefresh(authorization)) {
|
||||
TokenCacheUtils.addWithTtl(authorization, 1L);
|
||||
TokenCacheUtils.remove(authorization);
|
||||
authorization = refreshToken(request, response);
|
||||
}
|
||||
JWTToken token = new JWTToken(authorization);
|
||||
|
@ -148,7 +148,7 @@ public class AuthServer implements AuthApi {
|
||||
AccountLockStatus lockStatus = authUserService.recordLoginFail(username, 0);
|
||||
DataEaseException.throwException(appendLoginErrorMsg(Translator.get("i18n_id_or_pwd_error"), lockStatus));
|
||||
}
|
||||
if(user.getIsAdmin() && user.getPassword().equals("40b8893ea9ebc2d631c4bb42bb1e8996")){
|
||||
if (user.getIsAdmin() && user.getPassword().equals("40b8893ea9ebc2d631c4bb42bb1e8996")) {
|
||||
result.put("passwordModified", false);
|
||||
}
|
||||
}
|
||||
@ -237,7 +237,7 @@ public class AuthServer implements AuthApi {
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = "success";
|
||||
}
|
||||
TokenCacheUtils.remove(token);
|
||||
TokenCacheUtils.add(token, userId);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
@ -291,7 +291,7 @@ public class AuthServer implements AuthApi {
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = "success";
|
||||
}
|
||||
TokenCacheUtils.remove(token);
|
||||
TokenCacheUtils.add(token, userId);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
|
@ -10,7 +10,6 @@ import com.auth0.jwt.interfaces.Verification;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.commons.utils.TokenCacheUtils;
|
||||
import io.dataease.exception.DataEaseException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -68,7 +67,8 @@ public class JWTUtils {
|
||||
|
||||
public static boolean needRefresh(String token) {
|
||||
Date exp = JWTUtils.getExp(token);
|
||||
return new Date().getTime() >= exp.getTime();
|
||||
Long advanceTime = 5000L;
|
||||
return (new Date().getTime() + advanceTime) >= exp.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +119,6 @@ public class JWTUtils {
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId());
|
||||
String sign = builder.withExpiresAt(date).sign(algorithm);
|
||||
TokenCacheUtils.add(sign, tokenInfo.getUserId());
|
||||
return sign;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -3,36 +3,76 @@ package io.dataease.commons.utils;
|
||||
import io.dataease.listener.util.CacheUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@Component
|
||||
public class TokenCacheUtils {
|
||||
|
||||
|
||||
private static final String KEY = "sys_token_store";
|
||||
private static final String DELAY_KEY = "sys_token_store_delay";
|
||||
|
||||
private static String cacheType;
|
||||
|
||||
private static Long expTime;
|
||||
|
||||
@Value("${spring.cache.type:ehcache}")
|
||||
public void setCacheType(String cacheType) {
|
||||
TokenCacheUtils.cacheType = cacheType;
|
||||
}
|
||||
|
||||
@Value("${dataease.login_timeout:480}")
|
||||
public void setExpTime(Long expTime) {
|
||||
TokenCacheUtils.expTime = expTime;
|
||||
}
|
||||
|
||||
private static boolean useRedis() {
|
||||
return StringUtils.equals(cacheType, "redis");
|
||||
}
|
||||
|
||||
|
||||
private static ValueOperations cacheHandler() {
|
||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
||||
ValueOperations valueOperations = redisTemplate.opsForValue();
|
||||
return valueOperations;
|
||||
}
|
||||
|
||||
public static void add(String token, Long userId) {
|
||||
CacheUtils.put(KEY, token, userId, null, null);
|
||||
if (useRedis()) {
|
||||
ValueOperations valueOperations = cacheHandler();
|
||||
valueOperations.set(KEY + token, userId, expTime, TimeUnit.MINUTES);
|
||||
return;
|
||||
}
|
||||
|
||||
Long time = expTime * 60;
|
||||
CacheUtils.put(KEY, token, userId, time.intValue(), null);
|
||||
|
||||
}
|
||||
|
||||
public static void remove(String token) {
|
||||
if (useRedis()) {
|
||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
||||
String key = KEY + token;
|
||||
if (redisTemplate.hasKey(key)) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
CacheUtils.remove(KEY, token);
|
||||
}
|
||||
|
||||
public static boolean validate(String token) {
|
||||
public static boolean invalid(String token) {
|
||||
if (useRedis()) {
|
||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
||||
return redisTemplate.hasKey(KEY + token);
|
||||
}
|
||||
Object sys_token_store = CacheUtils.get(KEY, token);
|
||||
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString());
|
||||
}
|
||||
|
||||
public static boolean validate(String token, Long userId) {
|
||||
Object sys_token_store = CacheUtils.get(KEY, token);
|
||||
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString()) && userId == Long.parseLong(sys_token_store.toString());
|
||||
}
|
||||
|
||||
public static void addWithTtl(String token, Long userId) {
|
||||
CacheUtils.put(DELAY_KEY, token, userId, 3, 5);
|
||||
}
|
||||
|
||||
public static boolean validateDelay(String token) {
|
||||
Object tokenObj = CacheUtils.get(DELAY_KEY, token);
|
||||
return ObjectUtils.isNotEmpty(tokenObj) && StringUtils.isNotBlank(tokenObj.toString());
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,13 @@ import {
|
||||
changeFavicon
|
||||
} from '@/utils/index'
|
||||
import Layout from '@/layout/index'
|
||||
import { getSysUI } from '@/utils/auth'
|
||||
import {
|
||||
getSysUI
|
||||
} from '@/utils/auth'
|
||||
|
||||
import { getSocket } from '@/websocket'
|
||||
import {
|
||||
getSocket
|
||||
} from '@/websocket'
|
||||
|
||||
NProgress.configure({
|
||||
showSpinner: false
|
||||
@ -53,14 +57,19 @@ const routeBefore = (callBack) => {
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
router.beforeEach(async (to, from, next) => routeBefore(() => {
|
||||
router.beforeEach(async(to, from, next) => routeBefore(() => {
|
||||
// start progress bar
|
||||
NProgress.start()
|
||||
const mobileIgnores = ['/delink']
|
||||
const mobileIgnores = ['/delink', '/de-auto-login']
|
||||
const mobilePreview = '/preview/'
|
||||
const hasToken = getToken()
|
||||
|
||||
if (isMobile() && !to.path.includes(mobilePreview) && mobileIgnores.indexOf(to.path) === -1) {
|
||||
window.location.href = window.origin + '/app.html'
|
||||
let urlSuffix = '/app.html'
|
||||
if (hasToken) {
|
||||
urlSuffix += ('?detoken=' + hasToken)
|
||||
}
|
||||
window.location.href = window.origin + urlSuffix
|
||||
NProgress.done()
|
||||
}
|
||||
|
||||
@ -68,7 +77,7 @@ router.beforeEach(async (to, from, next) => routeBefore(() => {
|
||||
document.title = getPageTitle(to.meta.title)
|
||||
|
||||
// determine whether the user has logged in
|
||||
const hasToken = getToken()
|
||||
|
||||
if (hasToken) {
|
||||
if (to.path === '/login') {
|
||||
// if is logged in, redirect to the home page
|
||||
|
@ -143,3 +143,16 @@ export function parseLanguage() {
|
||||
if(language === 'sys') return uni.getLocale()
|
||||
return language
|
||||
}
|
||||
|
||||
export function getUrlParams(url){
|
||||
const Params = {}
|
||||
if(url.indexOf('?')>0){//判断是否有qurey
|
||||
let parmas = url.slice(url.indexOf('?')+1)//截取出query
|
||||
const paramlists = parmas.split('&')//分割键值对
|
||||
for (const param of paramlists) {
|
||||
let a = param.split('=')
|
||||
Object.assign(Params,{[a[0]]:a[1]})//将键值对封装成对象
|
||||
}
|
||||
}
|
||||
return Params
|
||||
}
|
||||
|
@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<view
|
||||
v-if="axiosFinished"
|
||||
:class="mobileBG ? 'content-de' : 'content'"
|
||||
:style="mobileBG ? {background:'url(' + mobileBG + ') no-repeat', 'backgroundSize':'cover'} : ''"
|
||||
>
|
||||
<view v-if="axiosFinished" :class="mobileBG ? 'content-de' : 'content'"
|
||||
:style="mobileBG ? {background:'url(' + mobileBG + ') no-repeat', 'backgroundSize':'cover'} : ''">
|
||||
|
||||
<view class="input-group" >
|
||||
<view class="input-group">
|
||||
<view class="input-row">
|
||||
<text class="welcome">{{$t('login.title')}}</text>
|
||||
</view>
|
||||
<view class="input-row border">
|
||||
<text class="title">{{$t('login.account')}}</text>
|
||||
<m-input class="m-input" type="text" clearable focus v-model="username" :placeholder="$t('login.accountPlaceholder')"></m-input>
|
||||
<m-input class="m-input" type="text" clearable focus v-model="username"
|
||||
:placeholder="$t('login.accountPlaceholder')"></m-input>
|
||||
</view>
|
||||
<view class="input-row border">
|
||||
<text class="title">{{$t('login.password')}}</text>
|
||||
<m-input type="password" displayable v-model="password" :placeholder="$t('login.passwordPlaceholder')"></m-input>
|
||||
<m-input type="password" displayable v-model="password" :placeholder="$t('login.passwordPlaceholder')">
|
||||
</m-input>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btn-row">
|
||||
<button type="primary" class="primary" :loading="loginBtnLoading" @tap="bindLogin">{{$t('login.loginbtn')}}</button>
|
||||
<button type="primary" class="primary" :loading="loginBtnLoading"
|
||||
@tap="bindLogin">{{$t('login.loginbtn')}}</button>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@ -32,8 +32,22 @@
|
||||
mapMutations
|
||||
} from 'vuex'
|
||||
import mInput from '../../components/m-input.vue'
|
||||
import {login, getInfo, getPublicKey, getUIinfo } from '@/api/auth'
|
||||
import {encrypt, setLocalPK, getLocalPK, setToken, getToken, setUserInfo, getUserInfo } from '@/common/utils'
|
||||
import {
|
||||
login,
|
||||
getInfo,
|
||||
getPublicKey,
|
||||
getUIinfo
|
||||
} from '@/api/auth'
|
||||
import {
|
||||
encrypt,
|
||||
setLocalPK,
|
||||
getLocalPK,
|
||||
setToken,
|
||||
getToken,
|
||||
setUserInfo,
|
||||
getUserInfo,
|
||||
getUrlParams
|
||||
} from '@/common/utils'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -46,27 +60,25 @@
|
||||
password: '',
|
||||
mobileBG: null,
|
||||
axiosFinished: false
|
||||
|
||||
}
|
||||
},
|
||||
computed: mapState(['forcedLogin', 'hasLogin', 'univerifyErrorMsg', 'hideUniverify']),
|
||||
|
||||
onLoad() {
|
||||
uni.showLoading({
|
||||
title: this.$t('commons.loading')
|
||||
});
|
||||
this.loadUiInfo()
|
||||
this.loadPublicKey()
|
||||
if(getToken() && getUserInfo()) {
|
||||
if (!this.autoLogin() && getToken() && getUserInfo()) {
|
||||
this.toMain()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapMutations(['login']),
|
||||
|
||||
async loginByPwd() {
|
||||
|
||||
if (this.username.length < 1) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
@ -87,7 +99,7 @@
|
||||
};
|
||||
this.loginBtnLoading = true
|
||||
login(data).then(res => {
|
||||
if(res.success) {
|
||||
if (res.success) {
|
||||
setToken(res.data.token)
|
||||
this.toMain()
|
||||
}
|
||||
@ -99,7 +111,6 @@
|
||||
title: error.response.data.message,
|
||||
});
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
bindLogin() {
|
||||
@ -113,16 +124,13 @@
|
||||
url: '../tabBar/home/index',
|
||||
});
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
loadUiInfo() {
|
||||
getUIinfo().then(res => {
|
||||
|
||||
|
||||
const list = res.data
|
||||
list.forEach(item => {
|
||||
if(item.paramKey === 'ui.mobileBG' && item.paramValue) {
|
||||
if (item.paramKey === 'ui.mobileBG' && item.paramValue) {
|
||||
this.mobileBG = '/system/ui/image/' + item.paramValue
|
||||
return false
|
||||
}
|
||||
@ -136,13 +144,22 @@
|
||||
},
|
||||
|
||||
loadPublicKey() {
|
||||
if(!getLocalPK()) {
|
||||
if (!getLocalPK()) {
|
||||
getPublicKey().then(res => {
|
||||
setLocalPK(res.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
autoLogin() {
|
||||
const url = window.location.href
|
||||
const param = getUrlParams(url)
|
||||
if (param?.detoken) {
|
||||
setToken(param.detoken)
|
||||
this.toMain()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
},
|
||||
onReady() {
|
||||
@ -152,7 +169,7 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import "@/components/m-icon/m-icon.css";
|
||||
@import "@/components/m-icon/m-icon.css";
|
||||
|
||||
/*每个页面公共css */
|
||||
page {
|
||||
@ -299,6 +316,7 @@
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-type {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -376,6 +394,7 @@
|
||||
position: relative;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
padding-left: 15px;
|
||||
font-size: x-large;
|
||||
|
Loading…
Reference in New Issue
Block a user