diff --git a/backend/pom.xml b/backend/pom.xml
index 8b1075bb04..c814656394 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -314,7 +314,17 @@
json-schema-validator
2.2.6
-->
-
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
+ net.sf.ehcache
+ ehcache
+ 2.9.1
+
diff --git a/backend/src/main/java/io/dataease/Application.java b/backend/src/main/java/io/dataease/Application.java
index 635212b880..d48da83dbc 100644
--- a/backend/src/main/java/io/dataease/Application.java
+++ b/backend/src/main/java/io/dataease/Application.java
@@ -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
diff --git a/backend/src/main/java/io/dataease/auth/api/AuthApi.java b/backend/src/main/java/io/dataease/auth/api/AuthApi.java
index f27473767e..f3e2a977e0 100644
--- a/backend/src/main/java/io/dataease/auth/api/AuthApi.java
+++ b/backend/src/main/java/io/dataease/auth/api/AuthApi.java
@@ -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();
diff --git a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
index 9c9fed8526..2311e1f449 100644
--- a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
+++ b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
@@ -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 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");
diff --git a/backend/src/main/java/io/dataease/auth/config/RsaProperties.java b/backend/src/main/java/io/dataease/auth/config/RsaProperties.java
new file mode 100644
index 0000000000..fc60282687
--- /dev/null
+++ b/backend/src/main/java/io/dataease/auth/config/RsaProperties.java
@@ -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;
+ }
+}
diff --git a/backend/src/main/java/io/dataease/auth/config/ShiroConfig.java b/backend/src/main/java/io/dataease/auth/config/ShiroConfig.java
index 11366f935c..c8cdc9214f 100644
--- a/backend/src/main/java/io/dataease/auth/config/ShiroConfig.java
+++ b/backend/src/main/java/io/dataease/auth/config/ShiroConfig.java
@@ -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");
diff --git a/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java b/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
new file mode 100644
index 0000000000..83d4dc0e96
--- /dev/null
+++ b/backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
@@ -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;
+ }
+}
diff --git a/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java b/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
index a89e7673fa..7a0602d105 100644
--- a/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
+++ b/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
@@ -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());
}
}
diff --git a/backend/src/main/java/io/dataease/auth/server/AuthServer.java b/backend/src/main/java/io/dataease/auth/server/AuthServer.java
index 11453e1886..bdb56b337b 100644
--- a/backend/src/main/java/io/dataease/auth/server/AuthServer.java
+++ b/backend/src/main/java/io/dataease/auth/server/AuthServer.java
@@ -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 result = new HashMap<>();
- result.put("token", JWTUtils.sign(username, realPwd));*/
- String token = JWTUtils.sign(username, realPwd);
- ServletUtils.setToken(token);
Map 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 currentRoleDtos = authUserService.roleInfos(user.getUserId());
List permissions = authUserService.permissions(user.getUserId());
@@ -64,7 +67,7 @@ public class AuthServer implements AuthApi {
return currentUserDto;
}
- @PostMapping("/logout")
+ @Override
public String logout(){
return "success";
}
diff --git a/backend/src/main/java/io/dataease/auth/service/AuthUserService.java b/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
index fe04b1aca2..2eb887365d 100644
--- a/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
+++ b/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
@@ -9,7 +9,9 @@ public interface AuthUserService {
- SysUserEntity getUser(String username);
+ SysUserEntity getUserById(Long userId);
+
+ SysUserEntity getUserByName(String username);
List roles(Long userId);
diff --git a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
index 314be618c6..e4fde7aba2 100644
--- a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
+++ b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
@@ -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 roles(Long userId){
return authMapper.roleCodes(userId);
diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
index fb271b508a..83cb7d8c34 100644
--- a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
+++ b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
@@ -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 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;
}
diff --git a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
index 53a277ac1f..67e27b8752 100644
--- a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
+++ b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
@@ -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);
diff --git a/backend/src/main/java/io/dataease/auth/util/RsaUtil.java b/backend/src/main/java/io/dataease/auth/util/RsaUtil.java
new file mode 100644
index 0000000000..577693cc48
--- /dev/null
+++ b/backend/src/main/java/io/dataease/auth/util/RsaUtil.java
@@ -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);
+ }
+}
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.java b/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.java
index 59bab3da68..050702436a 100644
--- a/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.java
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.java
@@ -15,11 +15,12 @@ public interface AuthMapper {
List roleCodes(@Param("userId") Long userId);
-
List permissions(@Param("userId") Long userId);
- SysUserEntity findUser(@Param("username") String username);
+ SysUserEntity findUser(@Param("userId") Long userId);
+
+ SysUserEntity findUserByName(@Param("username") String username);
List roles(@Param("userId") Long userId);
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.xml b/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.xml
index 4eacbdf053..0c5525e397 100644
--- a/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.xml
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/AuthMapper.xml
@@ -21,6 +21,10 @@
+
+
diff --git a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java
index adbfb5ce39..5fcc32d725 100644
--- a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java
+++ b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java
@@ -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;
}
diff --git a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java
index a1c8c8d6d0..4750140d4c 100644
--- a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java
+++ b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java
@@ -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);
+ }
}
diff --git a/backend/src/main/java/io/dataease/controller/sys/request/SysUserPwdRequest.java b/backend/src/main/java/io/dataease/controller/sys/request/SysUserPwdRequest.java
new file mode 100644
index 0000000000..2627deeede
--- /dev/null
+++ b/backend/src/main/java/io/dataease/controller/sys/request/SysUserPwdRequest.java
@@ -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;
+
+
+}
diff --git a/backend/src/main/java/io/dataease/service/sys/SysUserService.java b/backend/src/main/java/io/dataease/service/sys/SysUserService.java
index f6cbaca31a..ba7f4d3fd4 100644
--- a/backend/src/main/java/io/dataease/service/sys/SysUserService.java
+++ b/backend/src/main/java/io/dataease/service/sys/SysUserService.java
@@ -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);
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index ac1943006c..df77d81e6d 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -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
diff --git a/backend/src/main/resources/ehcache/ehcache.xml b/backend/src/main/resources/ehcache/ehcache.xml
new file mode 100644
index 0000000000..6af1c3769d
--- /dev/null
+++ b/backend/src/main/resources/ehcache/ehcache.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
index dc68f96da9..16bc7e2550 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -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",
diff --git a/frontend/src/api/system/user.js b/frontend/src/api/system/user.js
index eaa7473916..248b7ddaa5 100644
--- a/frontend/src/api/system/user.js
+++ b/frontend/src/api/system/user.js
@@ -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) {
diff --git a/frontend/src/assets/401_images/401.gif b/frontend/src/assets/401_images/401.gif
new file mode 100644
index 0000000000..cd6e0d9433
Binary files /dev/null and b/frontend/src/assets/401_images/401.gif differ
diff --git a/frontend/src/permission.js b/frontend/src/permission.js
index 00b155fa3b..b99ea5fa91 100644
--- a/frontend/src/permission.js
+++ b/frontend/src/permission.js
@@ -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
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index f023b5a7e4..26ae503f3e 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -53,6 +53,11 @@ export const constantRoutes = [
component: () => import('@/views/404'),
hidden: true
},
+ {
+ path: '/401',
+ component: (resolve) => require(['@/views/401'], resolve),
+ hidden: true
+ },
{
path: '/',
diff --git a/frontend/src/settings.js b/frontend/src/settings.js
index d70d24992f..305169c13e 100644
--- a/frontend/src/settings.js
+++ b/frontend/src/settings.js
@@ -1,5 +1,6 @@
module.exports = {
TokenKey: 'Authorization',
+ RefreshTokenKey: 'refreshauthorization',
title: 'DATA_EASE',
/**
diff --git a/frontend/src/store/modules/user.js b/frontend/src/store/modules/user.js
index ee02cef92a..ab250c4e0f 100644
--- a/frontend/src/store/modules/user.js
+++ b/frontend/src/store/modules/user.js
@@ -60,6 +60,10 @@ const actions = {
})
})
},
+ refreshToken({ commit }, token) {
+ commit('SET_TOKEN', token)
+ setToken(token)
+ },
// get user info
getInfo({ commit, state }) {
diff --git a/frontend/src/utils/request.js b/frontend/src/utils/request.js
index 837302bfad..05313732a2 100644
--- a/frontend/src/utils/request.js
+++ b/frontend/src/utils/request.js
@@ -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'
}
}
diff --git a/frontend/src/utils/rsaEncrypt.js b/frontend/src/utils/rsaEncrypt.js
new file mode 100644
index 0000000000..83db4809c9
--- /dev/null
+++ b/frontend/src/utils/rsaEncrypt.js
@@ -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)
+}
+
diff --git a/frontend/src/views/401.vue b/frontend/src/views/401.vue
new file mode 100644
index 0000000000..8a3b69e09a
--- /dev/null
+++ b/frontend/src/views/401.vue
@@ -0,0 +1,89 @@
+
+
+
+ 返回
+
+
+
+
+ Oops!
+
+ 你没有权限去该页面
+ 如有不满请联系你领导
+
+ - 或者你可以去:
+ -
+
+ 回首页
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/login/index.vue b/frontend/src/views/login/index.vue
index 7917492114..891b3f5b8b 100644
--- a/frontend/src/views/login/index.vue
+++ b/frontend/src/views/login/index.vue
@@ -50,7 +50,7 @@