forked from github/dataease
feat: 完善token续命刷新机制
This commit is contained in:
parent
f46912392c
commit
150b4c3982
@ -314,7 +314,17 @@
|
||||
<artifactId>json-schema-validator</artifactId>
|
||||
<version>2.2.6</version>
|
||||
</dependency>-->
|
||||
|
||||
<!--开启 cache 缓存 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<!-- ehcache 缓存 -->
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -5,9 +5,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@EnableCaching
|
||||
@SpringBootApplication(exclude = {
|
||||
QuartzAutoConfiguration.class,
|
||||
LdapAutoConfiguration.class
|
||||
|
@ -14,7 +14,7 @@ public interface AuthApi {
|
||||
|
||||
|
||||
@PostMapping("/login")
|
||||
Object login(LoginDto loginDto);
|
||||
Object login(LoginDto loginDto) throws Exception;
|
||||
|
||||
|
||||
@PostMapping("/userInfo")
|
||||
@ -23,6 +23,9 @@ public interface AuthApi {
|
||||
@GetMapping("/isLogin")
|
||||
Boolean isLogin();
|
||||
|
||||
@PostMapping("/logout")
|
||||
String logout();
|
||||
|
||||
|
||||
@GetMapping("/test")
|
||||
String test();
|
||||
|
@ -2,6 +2,7 @@ package io.dataease.auth.config;
|
||||
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
@ -34,9 +35,8 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
//验证资源权限
|
||||
@Override
|
||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||
String username = JWTUtils.getUsername(principals.toString());
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
Long userId = user.getUserId();
|
||||
Long userId = JWTUtils.tokenInfoByToken(principals.toString()).getUserId();
|
||||
//SysUserEntity user = authUserService.getUserById(userId);
|
||||
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
|
||||
Set<String> role = authUserService.roles(userId).stream().collect(Collectors.toSet());
|
||||
simpleAuthorizationInfo.addRoles(role);
|
||||
@ -50,12 +50,14 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
|
||||
String token = (String) auth.getCredentials();
|
||||
// 解密获得username,用于和数据库进行对比
|
||||
String username = JWTUtils.getUsername(token);
|
||||
TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token);
|
||||
Long userId = tokenInfo.getUserId();
|
||||
String username = tokenInfo.getUsername();
|
||||
if (username == null) {
|
||||
throw new AuthenticationException("token invalid");
|
||||
}
|
||||
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
SysUserEntity user = authUserService.getUserById(userId);
|
||||
if (user == null) {
|
||||
throw new AuthenticationException("User didn't existed!");
|
||||
}
|
||||
@ -66,7 +68,7 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (! JWTUtils.verify(token, username, pass)) {
|
||||
if (! JWTUtils.verify(token, tokenInfo, pass)) {
|
||||
throw new AuthenticationException("Username or password error");
|
||||
}
|
||||
return new SimpleAuthenticationInfo(token, token, "f2cReam");
|
||||
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.auth.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
public class RsaProperties {
|
||||
|
||||
public static String privateKey;
|
||||
|
||||
@Value("${rsa.private_key}")
|
||||
public void setPrivateKey(String privateKey) {
|
||||
RsaProperties.privateKey = privateKey;
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ public class ShiroConfig {
|
||||
|
||||
|
||||
|
||||
|
||||
@Bean("securityManager")
|
||||
public DefaultWebSecurityManager getManager(F2CRealm f2cRealm) {
|
||||
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
|
||||
@ -49,6 +50,7 @@ public class ShiroConfig {
|
||||
filterMap.put("f2cPerms", new F2CPermissionsFilter());
|
||||
//filterMap.put("f2cRoles", new F2CRolesFilter());
|
||||
filterMap.put("jwt", new JWTFilter());
|
||||
/*filterMap.put("jwt", jwtFilter);*/
|
||||
filterMap.put("logout", new F2CLogoutFilter());
|
||||
factoryBean.setSecurityManager(securityManager);
|
||||
factoryBean.setUnauthorizedUrl("/permissionMiss");
|
||||
|
21
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
Normal file
21
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
Normal file
@ -0,0 +1,21 @@
|
||||
package io.dataease.auth.entity;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class TokenInfo implements Serializable {
|
||||
|
||||
private String username;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long lastLoginTime;
|
||||
|
||||
public String format(){
|
||||
return username + "," +userId;
|
||||
}
|
||||
}
|
@ -1,25 +1,31 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
|
||||
|
||||
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/*@Autowired
|
||||
private AuthUserService authUserService;*/
|
||||
|
||||
|
||||
/**
|
||||
* 判断用户是否想要登入。
|
||||
@ -67,25 +73,22 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String refreshToken(ServletRequest request, ServletResponse response) {
|
||||
private String refreshToken(ServletRequest request, ServletResponse response) throws Exception{
|
||||
// 获取AccessToken(Shiro中getAuthzHeader方法已经实现)
|
||||
String token = this.getAuthzHeader(request);
|
||||
// 获取当前Token的帐号信息
|
||||
String username = JWTUtils.getUsername(token);
|
||||
String password = "123456";
|
||||
try {
|
||||
String newToken = JWTUtils.sign(username, password);
|
||||
JWTToken jwtToken = new JWTToken(newToken);
|
||||
this.getSubject(request, response).login(jwtToken);
|
||||
// 设置响应的Header头新Token
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
httpServletResponse.addHeader("Access-Control-Expose-Headers", "Authorization");
|
||||
httpServletResponse.setHeader("Authorization", newToken);
|
||||
return newToken;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token);
|
||||
AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class);
|
||||
SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId());
|
||||
String password = user.getPassword();
|
||||
String newToken = JWTUtils.sign(tokenInfo, password);
|
||||
JWTToken jwtToken = new JWTToken(newToken);
|
||||
this.getSubject(request, response).login(jwtToken);
|
||||
// 设置响应的Header头新Token
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
httpServletResponse.addHeader("Access-Control-Expose-Headers", "RefreshAuthorization");
|
||||
httpServletResponse.setHeader("RefreshAuthorization", newToken);
|
||||
return newToken;
|
||||
}
|
||||
|
||||
|
||||
@ -113,8 +116,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
private void response401(ServletRequest req, ServletResponse resp) {
|
||||
try {
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
|
||||
httpServletResponse.sendRedirect("/401");
|
||||
} catch (IOException e) {
|
||||
httpServletResponse.addHeader("Access-Control-Expose-Headers", "authentication-status");
|
||||
httpServletResponse.setHeader("authentication-status", "invalid");
|
||||
httpServletResponse.setStatus(401);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,18 @@ import io.dataease.auth.api.AuthApi;
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.dataease.auth.config.RsaProperties;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.auth.util.RsaUtil;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.HashMap;
|
||||
@ -26,36 +30,35 @@ public class AuthServer implements AuthApi {
|
||||
|
||||
|
||||
@Override
|
||||
public Object login(@RequestBody LoginDto loginDto) {
|
||||
public Object login(@RequestBody LoginDto loginDto) throws Exception {
|
||||
String username = loginDto.getUsername();
|
||||
String password = loginDto.getPassword();
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
SysUserEntity user = authUserService.getUserByName(username);
|
||||
String realPwd = user.getPassword();
|
||||
if (StringUtils.isEmpty(realPwd)){
|
||||
if (ObjectUtils.isEmpty(user)){
|
||||
throw new RuntimeException("没有该用户!");
|
||||
}
|
||||
/*String pwd = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, password);
|
||||
String realPass = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, realPwd);
|
||||
if (!StrUtil.equals(pwd, realPass)){
|
||||
throw new RuntimeException("密码错误!");
|
||||
}*/
|
||||
if (!StringUtils.equals(realPwd, password)){
|
||||
//私钥解密
|
||||
String pwd = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, password);
|
||||
//md5加密
|
||||
pwd = CodingUtil.md5(pwd);
|
||||
|
||||
if (!StringUtils.equals(pwd, realPwd)){
|
||||
throw new RuntimeException("密码错误!");
|
||||
}
|
||||
/*Map<String,Object> result = new HashMap<>();
|
||||
result.put("token", JWTUtils.sign(username, realPwd));*/
|
||||
String token = JWTUtils.sign(username, realPwd);
|
||||
ServletUtils.setToken(token);
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(username).lastLoginTime(System.currentTimeMillis()).build();
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd);
|
||||
result.put("token", token);
|
||||
ServletUtils.setToken(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurrentUserDto userInfo() {
|
||||
String token = ServletUtils.getToken();
|
||||
String username = JWTUtils.getUsername(token);
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
Long userId = JWTUtils.tokenInfoByToken(token).getUserId();
|
||||
SysUserEntity user = authUserService.getUserById(userId);
|
||||
CurrentUserDto currentUserDto = BeanUtils.copyBean(new CurrentUserDto(), user);
|
||||
List<CurrentRoleDto> currentRoleDtos = authUserService.roleInfos(user.getUserId());
|
||||
List<String> permissions = authUserService.permissions(user.getUserId());
|
||||
@ -64,7 +67,7 @@ public class AuthServer implements AuthApi {
|
||||
return currentUserDto;
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
@Override
|
||||
public String logout(){
|
||||
return "success";
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ public interface AuthUserService {
|
||||
|
||||
|
||||
|
||||
SysUserEntity getUser(String username);
|
||||
SysUserEntity getUserById(Long userId);
|
||||
|
||||
SysUserEntity getUserByName(String username);
|
||||
|
||||
List<String> roles(Long userId);
|
||||
|
||||
|
@ -5,6 +5,7 @@ import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.base.mapper.ext.AuthMapper;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -15,14 +16,27 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class AuthUserServiceImpl implements AuthUserService {
|
||||
|
||||
private final String USER_CACHE_NAME = "users_info";
|
||||
|
||||
@Resource
|
||||
private AuthMapper authMapper;
|
||||
|
||||
/**
|
||||
* 此处需被F2CRealm登录认证调用 也就是说每次请求都会被调用 所以最好加上缓存
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
@Cacheable(value = USER_CACHE_NAME, key = "'user' + #userId" )
|
||||
@Override
|
||||
public SysUserEntity getUserById(Long userId){
|
||||
return authMapper.findUser(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysUserEntity getUser(String username){
|
||||
return authMapper.findUser(username);
|
||||
public SysUserEntity getUserByName(String username) {
|
||||
return authMapper.findUserByName(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> roles(Long userId){
|
||||
return authMapper.roleCodes(userId);
|
||||
|
@ -30,10 +30,14 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
filterChainDefinitionMap.put("/v3/**","anon");
|
||||
filterChainDefinitionMap.put("/static/**", "anon");
|
||||
|
||||
|
||||
// filterChainDefinitionMap.put("/401", "anon");
|
||||
// filterChainDefinitionMap.put("/404", "anon");
|
||||
// 登陆
|
||||
// filterChainDefinitionMap.put("/api/auth/logout", "anon");
|
||||
filterChainDefinitionMap.put("/api/auth/login", "anon");
|
||||
// 退出
|
||||
//filterChainDefinitionMap.put("/logout", "anon");
|
||||
|
||||
// 放行未授权接口,重定向使用
|
||||
filterChainDefinitionMap.put("/unauth", "anon");
|
||||
filterChainDefinitionMap.put("/display/**", "anon");
|
||||
@ -43,7 +47,6 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
// 被挤下线
|
||||
filterChainDefinitionMap.put("/downline", "anon");
|
||||
// 放行 end ----------------------------------------------------------
|
||||
filterChainDefinitionMap.put("/logout", "logout");
|
||||
|
||||
/*List<ExtPermissionBean> extPermissionBeans = extUserMapper.getPermissions();
|
||||
|
||||
@ -53,7 +56,7 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
filterChainDefinitionMap.put(item.getPath(), "jwt," + f2cPerms);
|
||||
});
|
||||
*/
|
||||
|
||||
filterChainDefinitionMap.put("/api/auth/logout", "logout");
|
||||
filterChainDefinitionMap.put("/**", "jwt");
|
||||
return filterChainDefinitionMap;
|
||||
}
|
||||
|
@ -5,15 +5,19 @@ import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class JWTUtils {
|
||||
|
||||
|
||||
// 过期时间5分钟
|
||||
private static final long EXPIRE_TIME = 5*60*1000;
|
||||
|
||||
// token过期时间5分钟 (过期会自动刷新续命 目的是避免一直都是同一个token )
|
||||
private static final long EXPIRE_TIME = 1*60*1000;
|
||||
// 登录间隔时间 超过这个时间强制重新登录
|
||||
private static final long Login_Interval = 2*60*1000;
|
||||
|
||||
|
||||
/**
|
||||
@ -22,10 +26,12 @@ public class JWTUtils {
|
||||
* @param secret 用户的密码
|
||||
* @return 是否正确
|
||||
*/
|
||||
public static boolean verify(String token, String username, String secret) {
|
||||
public static boolean verify(String token, TokenInfo tokenInfo, String secret) {
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
JWTVerifier verifier = JWT.require(algorithm)
|
||||
.withClaim("username", username)
|
||||
.withClaim("lastLoginTime", tokenInfo.getLastLoginTime())
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId())
|
||||
.build();
|
||||
verifier.verify(token);
|
||||
return true;
|
||||
@ -35,18 +41,22 @@ public class JWTUtils {
|
||||
* 获得token中的信息无需secret解密也能获得
|
||||
* @return token中包含的用户名
|
||||
*/
|
||||
public static String getUsername(String token) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
return jwt.getClaim("username").asString();
|
||||
} catch (JWTDecodeException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
public static TokenInfo tokenInfoByToken(String token) {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
String username = jwt.getClaim("username").asString();
|
||||
Long userId = jwt.getClaim("userId").asLong();
|
||||
Long lastLoginTime = jwt.getClaim("lastLoginTime").asLong();
|
||||
if (StringUtils.isEmpty(username) || ObjectUtils.isEmpty(userId) || ObjectUtils.isEmpty(lastLoginTime)){
|
||||
throw new RuntimeException("token格式错误!");
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().username(username).userId(userId).lastLoginTime(lastLoginTime).build();
|
||||
return tokenInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean needRefresh(String token){
|
||||
Date exp = JWTUtils.getExp(token);
|
||||
return new Date().getTime() >= exp.getTime();
|
||||
@ -64,17 +74,19 @@ public class JWTUtils {
|
||||
|
||||
/**
|
||||
* 生成签名,5min后过期
|
||||
* @param username 用户名
|
||||
* @param tokenInfo 用户信息
|
||||
* @param secret 用户的密码
|
||||
* @return 加密的token
|
||||
*/
|
||||
public static String sign(String username, String secret) {
|
||||
public static String sign(TokenInfo tokenInfo, String secret) {
|
||||
try {
|
||||
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
// 附带username信息
|
||||
return JWT.create()
|
||||
.withClaim("username", username)
|
||||
.withClaim("lastLoginTime", tokenInfo.getLastLoginTime())
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId())
|
||||
.withClaim("exp", date)
|
||||
.withExpiresAt(date)
|
||||
.sign(algorithm);
|
||||
|
29
backend/src/main/java/io/dataease/auth/util/RsaUtil.java
Normal file
29
backend/src/main/java/io/dataease/auth/util/RsaUtil.java
Normal file
@ -0,0 +1,29 @@
|
||||
package io.dataease.auth.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
|
||||
public class RsaUtil {
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param privateKeyText 私钥
|
||||
* @param text 待解密的文本
|
||||
* @return /
|
||||
* @throws Exception /
|
||||
*/
|
||||
public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
|
||||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
|
||||
return new String(result);
|
||||
}
|
||||
}
|
@ -15,11 +15,12 @@ public interface AuthMapper {
|
||||
List<String> roleCodes(@Param("userId") Long userId);
|
||||
|
||||
|
||||
|
||||
List<String> permissions(@Param("userId") Long userId);
|
||||
|
||||
|
||||
SysUserEntity findUser(@Param("username") String username);
|
||||
SysUserEntity findUser(@Param("userId") Long userId);
|
||||
|
||||
SysUserEntity findUserByName(@Param("username") String username);
|
||||
|
||||
|
||||
List<CurrentRoleDto> roles(@Param("userId") Long userId);
|
||||
|
@ -21,6 +21,10 @@
|
||||
|
||||
|
||||
<select id="findUser" resultMap="baseMap">
|
||||
select user_id, username,nick_name, dept_id, password, enabled,email, phone from sys_user where user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="findUserByName" resultMap="baseMap">
|
||||
select user_id, username,nick_name, dept_id, password, enabled,email, phone from sys_user where username = #{username}
|
||||
</select>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.dataease.commons.utils;
|
||||
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.base.domain.SysUser;
|
||||
import io.dataease.service.sys.SysUserService;
|
||||
@ -18,9 +19,9 @@ public class AuthUtils {
|
||||
|
||||
public static SysUser getUser(){
|
||||
String token = ServletUtils.getToken();
|
||||
String username = JWTUtils.getUsername(token);
|
||||
TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token);
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUsername(username);
|
||||
sysUser.setUserId(tokenInfo.getUserId());
|
||||
SysUser user = sysUserService.findOne(sysUser);
|
||||
return user;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.github.pagehelper.PageHelper;
|
||||
import io.dataease.commons.utils.PageUtils;
|
||||
import io.dataease.commons.utils.Pager;
|
||||
import io.dataease.controller.sys.request.SysUserCreateRequest;
|
||||
import io.dataease.controller.sys.request.SysUserPwdRequest;
|
||||
import io.dataease.controller.sys.request.SysUserStateRequest;
|
||||
import io.dataease.controller.sys.request.UserGridRequest;
|
||||
import io.dataease.controller.sys.response.SysUserGridResponse;
|
||||
@ -55,4 +56,11 @@ public class SysUserController {
|
||||
public void updateStatus(@RequestBody SysUserStateRequest request){
|
||||
sysUserService.updateStatus(request);
|
||||
}
|
||||
|
||||
@ApiOperation("更新用户密码")
|
||||
@PostMapping("/updatePwd")
|
||||
public void updatePwd(@RequestBody SysUserPwdRequest request){
|
||||
|
||||
sysUserService.updatePwd(request);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.controller.sys.request;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class SysUserPwdRequest implements Serializable {
|
||||
|
||||
private Long userId;
|
||||
private String password;
|
||||
private String repeatPassword;
|
||||
private String newPassword;
|
||||
|
||||
|
||||
}
|
@ -10,6 +10,7 @@ import io.dataease.base.mapper.ext.ExtSysUserMapper;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.controller.sys.request.SysUserCreateRequest;
|
||||
import io.dataease.controller.sys.request.SysUserPwdRequest;
|
||||
import io.dataease.controller.sys.request.SysUserStateRequest;
|
||||
import io.dataease.controller.sys.request.UserGridRequest;
|
||||
import io.dataease.controller.sys.response.SysUserGridResponse;
|
||||
@ -17,6 +18,7 @@ import io.dataease.controller.sys.response.SysUserRole;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import javax.annotation.Resource;
|
||||
@ -26,6 +28,7 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class SysUserService {
|
||||
|
||||
private final static String USER_CACHE_NAME = "users_info";
|
||||
private final static String DEFAULT_PWD = "DataEase123..";
|
||||
|
||||
@Resource
|
||||
@ -83,6 +86,33 @@ public class SysUserService {
|
||||
return sysUserMapper.updateByPrimaryKeySelective(sysUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码清楚缓存
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@CacheEvict(value = USER_CACHE_NAME, key = "'user' + #request.userId")
|
||||
public int updatePwd(SysUserPwdRequest request) {
|
||||
if (!StringUtils.equals(request.getPassword(), request.getRepeatPassword())){
|
||||
throw new RuntimeException("两次密码不一致");
|
||||
}
|
||||
SysUser temp = new SysUser();
|
||||
temp.setUserId(request.getUserId());
|
||||
SysUser user = findOne(temp);
|
||||
if (ObjectUtils.isEmpty(user)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
}
|
||||
if (!StringUtils.equals(request.getPassword(), user.getPassword())){
|
||||
throw new RuntimeException("密码错误");
|
||||
}
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserId(request.getUserId());
|
||||
sysUser.setPassword(CodingUtil.md5(request.getNewPassword()));
|
||||
return sysUserMapper.updateByPrimaryKeySelective(sysUser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 删除用户角色关联
|
||||
* @param userId
|
||||
@ -108,6 +138,7 @@ public class SysUserService {
|
||||
});
|
||||
}
|
||||
|
||||
@CacheEvict(value = USER_CACHE_NAME, key = "'user' + #userId")
|
||||
@Transactional
|
||||
public int delete(Long userId){
|
||||
deleteUserRoles(userId);
|
||||
|
@ -50,6 +50,10 @@ spring.servlet.multipart.max-request-size=500MB
|
||||
management.server.port=8083
|
||||
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==
|
||||
spring.cache.type=ehcache
|
||||
spring.cache.ehcache.config=classpath:/ehcache/ehcache.xml
|
||||
|
||||
|
||||
|
||||
|
49
backend/src/main/resources/ehcache/ehcache.xml
Normal file
49
backend/src/main/resources/ehcache/ehcache.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ehcache name="myEncache">
|
||||
|
||||
<!--
|
||||
diskStore:为缓存路径,ehcache分为内存和磁盘 2级,此属性定义磁盘的缓存位置
|
||||
user.home - 用户主目录
|
||||
user.dir - 用户当前工作目录
|
||||
java.io.tmpdir - 默认临时文件路径
|
||||
-->
|
||||
<!-- <diskStore path="D:/home/Tmp_Ehcache"/>-->
|
||||
<!--
|
||||
name:缓存名称。
|
||||
maxElementsInMemory:缓存最大数目
|
||||
maxElementsOnDisk:硬盘最大缓存个数。
|
||||
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
|
||||
overflowToDisk:是否保存到磁盘,当系统宕机时
|
||||
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
|
||||
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
|
||||
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
|
||||
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
|
||||
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
|
||||
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
|
||||
clearOnFlush:内存数量最大时是否清除。
|
||||
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
|
||||
FIFO,first in first out,这个是大家最熟的,先进先出。
|
||||
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
|
||||
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
|
||||
-->
|
||||
<defaultCache
|
||||
eternal="false"
|
||||
maxElementsInMemory="1000"
|
||||
overflowToDisk="false"
|
||||
diskPersistent="false"
|
||||
timeToIdleSeconds="0"
|
||||
timeToLiveSeconds="600"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
<cache
|
||||
name="users_info"
|
||||
eternal="false"
|
||||
maxElementsInMemory="100"
|
||||
overflowToDisk="false"
|
||||
diskPersistent="false"
|
||||
timeToIdleSeconds="0"
|
||||
timeToLiveSeconds="300"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
</ehcache>
|
@ -19,6 +19,7 @@
|
||||
"element-ui": "2.13.0",
|
||||
"fit2cloud-ui": "^0.1.12",
|
||||
"js-cookie": "2.2.0",
|
||||
"jsencrypt": "^3.0.0-rc.1",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"screenfull": "4.2.0",
|
||||
|
@ -4,7 +4,7 @@ const pathMap = {
|
||||
deletePath: '/api/user/delete/',
|
||||
createPath: '/api/user/create',
|
||||
updatePath: '/api/user/update',
|
||||
editPasswordPath: '/api/user/password',
|
||||
editPasswordPath: '/api/user/updatePwd',
|
||||
editStatusPath: '/api/user/updateStatus'
|
||||
}
|
||||
export function userLists(page, size, data) {
|
||||
|
BIN
frontend/src/assets/401_images/401.gif
Normal file
BIN
frontend/src/assets/401_images/401.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
@ -10,7 +10,7 @@ import { filterAsyncRouter } from '@/store/modules/permission'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
const whiteList = ['/login'] // no redirect whitelist
|
||||
const whiteList = ['/login', '/401', '/404'] // no redirect whitelist
|
||||
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
// start progress bar
|
||||
|
@ -53,6 +53,11 @@ export const constantRoutes = [
|
||||
component: () => import('@/views/404'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/401',
|
||||
component: (resolve) => require(['@/views/401'], resolve),
|
||||
hidden: true
|
||||
},
|
||||
|
||||
{
|
||||
path: '/',
|
||||
|
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
TokenKey: 'Authorization',
|
||||
RefreshTokenKey: 'refreshauthorization',
|
||||
title: 'DATA_EASE',
|
||||
|
||||
/**
|
||||
|
@ -60,6 +60,10 @@ const actions = {
|
||||
})
|
||||
})
|
||||
},
|
||||
refreshToken({ commit }, token) {
|
||||
commit('SET_TOKEN', token)
|
||||
setToken(token)
|
||||
},
|
||||
|
||||
// get user info
|
||||
getInfo({ commit, state }) {
|
||||
|
@ -9,6 +9,7 @@ import { tryShowLoading, tryHideLoading } from './loading'
|
||||
// import router from '@/router'
|
||||
|
||||
const TokenKey = Config.TokenKey
|
||||
const RefreshTokenKey = Config.RefreshTokenKey
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||
@ -34,6 +35,7 @@ service.interceptors.request.use(
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
error.config.loading && tryHideLoading(store.getters.currentPath)
|
||||
// do something with request error
|
||||
console.log(error) // for debug
|
||||
return Promise.reject(error)
|
||||
@ -50,12 +52,20 @@ const checkAuth = response => {
|
||||
})
|
||||
})
|
||||
}
|
||||
// token到期后自动续命 刷新token
|
||||
if (response.headers[RefreshTokenKey]) {
|
||||
const refreshToken = response.headers[RefreshTokenKey]
|
||||
store.dispatch('user/refreshToken', refreshToken)
|
||||
}
|
||||
}
|
||||
|
||||
const checkPermission = response => {
|
||||
// 请根据实际需求修改
|
||||
if (response.status === 403) {
|
||||
location.href = '/403'
|
||||
if (response.status === 404) {
|
||||
location.href = '/404'
|
||||
}
|
||||
if (response.status === 401) {
|
||||
location.href = '/401'
|
||||
}
|
||||
}
|
||||
|
||||
|
30
frontend/src/utils/rsaEncrypt.js
Normal file
30
frontend/src/utils/rsaEncrypt.js
Normal file
@ -0,0 +1,30 @@
|
||||
import JSEncrypt from 'jsencrypt/bin/jsencrypt'
|
||||
|
||||
// 密钥对生成 http://web.chacuo.net/netrsakeypair
|
||||
|
||||
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' +
|
||||
'2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=='
|
||||
|
||||
const privateKey = 'MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8\n' +
|
||||
'mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9p\n' +
|
||||
'B6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue\n' +
|
||||
'/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZ\n' +
|
||||
'UBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6\n' +
|
||||
'vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha\n' +
|
||||
'4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3\n' +
|
||||
'tTbklZkD2A=='
|
||||
|
||||
// 加密
|
||||
export function encrypt(txt) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPublicKey(publicKey) // 设置公钥
|
||||
return encryptor.encrypt(txt) // 对需要加密的数据进行加密
|
||||
}
|
||||
|
||||
// 解密
|
||||
export function decrypt(txt) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPrivateKey(privateKey)
|
||||
return encryptor.decrypt(txt)
|
||||
}
|
||||
|
89
frontend/src/views/401.vue
Normal file
89
frontend/src/views/401.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="errPage-container">
|
||||
<el-button icon="arrow-left" class="pan-back-btn" @click="back">
|
||||
返回
|
||||
</el-button>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<h1 class="text-jumbo text-ginormous">
|
||||
Oops!
|
||||
</h1>
|
||||
<h2>你没有权限去该页面</h2>
|
||||
<h6>如有不满请联系你领导</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li>或者你可以去:</li>
|
||||
<li class="link-type">
|
||||
<router-link to="/dashboard">
|
||||
回首页
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import errGif from '@/assets/401_images/401.gif'
|
||||
|
||||
export default {
|
||||
name: 'Page401',
|
||||
data() {
|
||||
return {
|
||||
errGif: errGif + '?' + +new Date()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
if (this.$route.query.noGoBack) {
|
||||
this.$router.push({ path: '/dashboard' })
|
||||
} else {
|
||||
this.$router.go(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.errPage-container {
|
||||
width: 800px;
|
||||
max-width: 100%;
|
||||
margin: 100px auto;
|
||||
.pan-back-btn {
|
||||
background: #008489;
|
||||
color: #fff;
|
||||
border: none!important;
|
||||
}
|
||||
.pan-gif {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
.pan-img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
.text-jumbo {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #484848;
|
||||
}
|
||||
.list-unstyled {
|
||||
font-size: 14px;
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
a {
|
||||
color: #008489;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -50,7 +50,7 @@
|
||||
|
||||
<script>
|
||||
import { validUsername } from '@/utils/validate'
|
||||
|
||||
import { encrypt } from '@/utils/rsaEncrypt'
|
||||
export default {
|
||||
name: 'Login',
|
||||
data() {
|
||||
@ -96,7 +96,12 @@ export default {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
this.$store.dispatch('user/login', this.loginForm).then(() => {
|
||||
const user = {
|
||||
username: this.loginForm.username,
|
||||
password: this.loginForm.password
|
||||
}
|
||||
user.password = encrypt(user.password)
|
||||
this.$store.dispatch('user/login', user).then(() => {
|
||||
this.$router.push({ path: this.redirect || '/' })
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
|
@ -4,65 +4,65 @@
|
||||
<ms-aside-container>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane name="PanelList">
|
||||
<span slot="label"><i class="el-icon-document"></i>列表</span>
|
||||
<PanelList @switchComponent="switchComponent"/>
|
||||
<span slot="label"><i class="el-icon-document" />列表</span>
|
||||
<PanelList @switchComponent="switchComponent" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="panels_star">
|
||||
<span slot="label"><i class="el-icon-star-off"></i>收藏</span>
|
||||
<span slot="label"><i class="el-icon-star-off" />收藏</span>
|
||||
开发中...
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="panels_share">
|
||||
<span slot="label"><i class="el-icon-share"></i>分享</span>
|
||||
<span slot="label"><i class="el-icon-share" />分享</span>
|
||||
开发中...
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane name="example">-->
|
||||
<!-- <span slot="label"><i class="el-icon-star-on"></i>示例</span>-->
|
||||
<!-- <group @switchComponent="switchComponent"/>-->
|
||||
<!-- </el-tab-pane>-->
|
||||
<!-- <el-tab-pane name="example">-->
|
||||
<!-- <span slot="label"><i class="el-icon-star-on"></i>示例</span>-->
|
||||
<!-- <group @switchComponent="switchComponent"/>-->
|
||||
<!-- </el-tab-pane>-->
|
||||
</el-tabs>
|
||||
|
||||
</ms-aside-container>
|
||||
|
||||
<ms-main-container>
|
||||
<!--<router-view/>-->
|
||||
<component :is="component" :param="param" @switchComponent="switchComponent"/>
|
||||
<component :is="component" :param="param" @switchComponent="switchComponent" />
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsMainContainer from '@/metersphere/common/components/MsMainContainer'
|
||||
import MsContainer from '@/metersphere/common/components/MsContainer'
|
||||
import MsAsideContainer from '@/metersphere/common/components/MsAsideContainer'
|
||||
import Group from './group/Group'
|
||||
import PanelList from './list/PanelList'
|
||||
import PanelView from './list/PanelView'
|
||||
import MsMainContainer from '@/metersphere/common/components/MsMainContainer'
|
||||
import MsContainer from '@/metersphere/common/components/MsContainer'
|
||||
import MsAsideContainer from '@/metersphere/common/components/MsAsideContainer'
|
||||
import Group from './group/Group'
|
||||
import PanelList from './list/PanelList'
|
||||
import PanelView from './list/PanelView'
|
||||
|
||||
export default {
|
||||
name: 'Panel',
|
||||
components: {MsMainContainer, MsContainer, MsAsideContainer, Group, PanelList,PanelView},
|
||||
data() {
|
||||
return {
|
||||
component: PanelView,
|
||||
param: {},
|
||||
activeName: 'PanelList'
|
||||
}
|
||||
export default {
|
||||
name: 'Panel',
|
||||
components: { MsMainContainer, MsContainer, MsAsideContainer, Group, PanelList, PanelView },
|
||||
data() {
|
||||
return {
|
||||
component: PanelView,
|
||||
param: {},
|
||||
activeName: 'PanelList'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
console.log(tab, event)
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
console.log(tab, event)
|
||||
},
|
||||
switchComponent(c) {
|
||||
console.log(c)
|
||||
this.param = c.param
|
||||
switch (c.name) {
|
||||
case 'PanelView':
|
||||
this.component = PanelView
|
||||
break
|
||||
}
|
||||
switchComponent(c) {
|
||||
console.log(c)
|
||||
this.param = c.param
|
||||
switch (c.name) {
|
||||
case 'PanelView':
|
||||
this.component = PanelView
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
Loading…
Reference in New Issue
Block a user