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

# Conflicts:
#	frontend/src/views/panel/index.vue
This commit is contained in:
wangjiahao 2021-03-08 18:44:13 +08:00
commit 0d3e1d093f
33 changed files with 461 additions and 77 deletions

View File

@ -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>

View File

@ -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

View File

@ -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();

View File

@ -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");

View File

@ -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;
}
}

View File

@ -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");

View 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;
}
}

View File

@ -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());
}
}

View File

@ -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";
}

View File

@ -9,7 +9,9 @@ public interface AuthUserService {
SysUserEntity getUser(String username);
SysUserEntity getUserById(Long userId);
SysUserEntity getUserByName(String username);
List<String> roles(Long userId);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View 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);
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View 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最少访问次数
FIFOfirst in first out这个是大家最熟的先进先出。
LFU Less Frequently Used就是上面例子中使用的策略直白一点就是讲一直以来最少被使用的。如上面所讲缓存的元素有一个hit属性hit值最小的将会被清出缓存。
LRULeast 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>

View File

@ -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",

View File

@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View File

@ -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

View File

@ -53,6 +53,11 @@ export const constantRoutes = [
component: () => import('@/views/404'),
hidden: true
},
{
path: '/401',
component: (resolve) => require(['@/views/401'], resolve),
hidden: true
},
{
path: '/',

View File

@ -1,5 +1,6 @@
module.exports = {
TokenKey: 'Authorization',
RefreshTokenKey: 'refreshauthorization',
title: 'DATA_EASE',
/**

View File

@ -60,6 +60,10 @@ const actions = {
})
})
},
refreshToken({ commit }, token) {
commit('SET_TOKEN', token)
setToken(token)
},
// get user info
getInfo({ commit, state }) {

View File

@ -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'
}
}

View 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)
}

View 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>

View File

@ -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(() => {