diff --git a/driver/pom.xml b/driver/pom.xml
index 4a5e386..9e03c51 100644
--- a/driver/pom.xml
+++ b/driver/pom.xml
@@ -91,6 +91,17 @@
shiro-spring
1.9.0
+
+ cn.hutool
+ hutool-all
+ 5.8.0
+
+
+ com.auth0
+ java-jwt
+ 3.8.3
+
+
diff --git a/driver/src/main/java/xyz/longicorn/driver/config/AuthFilter.java b/driver/src/main/java/xyz/longicorn/driver/config/AuthFilter.java
deleted file mode 100644
index d857d1f..0000000
--- a/driver/src/main/java/xyz/longicorn/driver/config/AuthFilter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package xyz.longicorn.driver.config;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.subject.Subject;
-import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
-
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-public class AuthFilter extends BasicHttpAuthenticationFilter {
-
- //判断是否允许通过
- @Override
- protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
- return super.isAccessAllowed(request, response, mappedValue);
- }
-
- //是否允许登录
- @Override
- protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
- return super.isLoginAttempt(request, response);
- }
-
- // 创建shiro token
- @Override
- protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
- return super.createToken(request, response);
- }
-
- //isAccessAllowed为false时调用,验证失败
- @Override
- protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
- this.sendChallenge(request, response);
- responseError(response, "he he !");
- return false;
- }
-
- //shiro验证成功调用
- @Override
- protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
- return super.onLoginSuccess(token, subject, request, response);
- }
-
- @Override
- protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
- if (!isLoginAttempt(request, response)) {
- responseError(response, "verify token failure");
- return false;
- }
- return super.preHandle(request, response);
- }
-
- private void setCors(ServletResponse response) {
- HttpServletResponse httpServletResponse = (HttpServletResponse) response;
-// httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true");
- httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
- httpServletResponse.addHeader("Access-Control-Allow-Methods", "*");
- httpServletResponse.addHeader("Access-Control-Allow-Headers", "*");
- }
-
- private void responseError(ServletResponse response, Object msg) {
- setCors(response);
- HttpServletResponse httpResponse = (HttpServletResponse) response;
- httpResponse.setStatus(401);
- httpResponse.setCharacterEncoding("UTF-8");
- httpResponse.setContentType("application/json;charset=UTF-8");
- try {
- String rj = msg instanceof String ? (String) msg : new ObjectMapper().writeValueAsString(msg);
- httpResponse.getWriter().append(rj);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/driver/src/main/java/xyz/longicorn/driver/config/RedisConfig.java b/driver/src/main/java/xyz/longicorn/driver/config/RedisConfig.java
new file mode 100644
index 0000000..cf2c151
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/config/RedisConfig.java
@@ -0,0 +1,106 @@
+package xyz.longicorn.driver.config;
+
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+//redis配置类
+@Configuration
+public class RedisConfig {
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+
+ RedisTemplate template = new RedisTemplate<>();
+ // 配置连接工厂
+ template.setConnectionFactory(factory);
+
+ //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
+ Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer(Object.class);
+
+ ObjectMapper om = new ObjectMapper();
+ // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
+ om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
+ //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+ om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
+ jackson.setObjectMapper(om);
+
+ // 值采用json序列化
+ template.setValueSerializer(jackson);
+ //使用StringRedisSerializer来序列化和反序列化redis的key值
+ template.setKeySerializer(new StringRedisSerializer());
+
+ // 设置hash key 和value序列化模式
+ template.setHashKeySerializer(new StringRedisSerializer());
+ template.setHashValueSerializer(jackson);
+ template.afterPropertiesSet();
+
+ return template;
+ }
+
+ /**
+ * 对hash类型的数据操作
+ *
+ * @param redisTemplate
+ * @return
+ */
+ @Bean
+ public HashOperations hashOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForHash();
+ }
+
+ /**
+ * 对redis字符串类型数据操作
+ *
+ * @param redisTemplate
+ * @return
+ */
+ @Bean
+ public ValueOperations valueOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForValue();
+ }
+
+ /**
+ * 对链表类型的数据操作
+ *
+ * @param redisTemplate
+ * @return
+ */
+ @Bean
+ public ListOperations listOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForList();
+ }
+
+ /**
+ * 对无序集合类型的数据操作
+ *
+ * @param redisTemplate
+ * @return
+ */
+ @Bean
+ public SetOperations setOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForSet();
+ }
+
+ /**
+ * 对有序集合类型的数据操作
+ *
+ * @param redisTemplate
+ * @return
+ */
+ @Bean
+ public ZSetOperations zSetOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForZSet();
+ }
+
+}
+
+
diff --git a/driver/src/main/java/xyz/longicorn/driver/config/ShiroConfig.java b/driver/src/main/java/xyz/longicorn/driver/config/ShiroConfig.java
deleted file mode 100644
index 8fb2505..0000000
--- a/driver/src/main/java/xyz/longicorn/driver/config/ShiroConfig.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package xyz.longicorn.driver.config;
-
-import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
-import org.apache.shiro.mgt.DefaultSubjectDAO;
-import org.apache.shiro.mgt.SecurityManager;
-import org.apache.shiro.realm.Realm;
-import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
-import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
-import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import javax.servlet.Filter;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-@Configuration
-public class ShiroConfig {
- @Autowired
- private UserRealm userRealm;
-
- //ShiroFilter过滤所有请求
- @Bean(name = "shiroFilterFactoryBean")
- public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- Map filterMap = new LinkedHashMap<>();
- filterMap.put("auth", new AuthFilter()); // 设置验证过滤器
-
- shiroFilterFactoryBean.setFilters(filterMap);
- //给ShiroFilter配置安全管理器
- shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
- //配置系统公共资源
- Map map = new HashMap();
- //匿名资源 一定是在受限资源上面
- map.put("/api/**", "anon");
- //受限资源需要认证和授权
- map.put("/**", "auth");
-
- // 设置认证界面路径
-// shiroFilterFactoryBean.setLoginUrl("/user/login");
- shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
- return shiroFilterFactoryBean;
- }
-
-
- @Bean
- public DefaultWebSecurityManager defaultWebSecurityManager(UserRealm userRealm) {
- //设置自定义Realm
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
- securityManager.setRealm(userRealm);
- //关闭shiro自带的session
- DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
- DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
- defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
- subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
- securityManager.setSubjectDAO(subjectDAO);
- return securityManager;
- }
-}
diff --git a/driver/src/main/java/xyz/longicorn/driver/controller/PreviewController.java b/driver/src/main/java/xyz/longicorn/driver/controller/PreviewController.java
index c6af329..9ac9c06 100644
--- a/driver/src/main/java/xyz/longicorn/driver/controller/PreviewController.java
+++ b/driver/src/main/java/xyz/longicorn/driver/controller/PreviewController.java
@@ -16,6 +16,7 @@ import java.io.FileInputStream;
// 根据文件生成预览
@Controller
@RestController
+@RequestMapping("/picture")
public class PreviewController {
@Resource
private FileService fileService;
diff --git a/driver/src/main/java/xyz/longicorn/driver/controller/UserController.java b/driver/src/main/java/xyz/longicorn/driver/controller/UserController.java
new file mode 100644
index 0000000..6dbcc3d
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/controller/UserController.java
@@ -0,0 +1,35 @@
+package xyz.longicorn.driver.controller;
+
+import cn.hutool.core.util.IdUtil;
+import lombok.SneakyThrows;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import xyz.longicorn.driver.dto.ApiResult;
+import xyz.longicorn.driver.dto.LoginModel;
+import xyz.longicorn.driver.pojo.LoginUser;
+import xyz.longicorn.driver.service.UserService;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/user")
+public class UserController {
+ @Resource
+ private UserService userService;
+
+ // @Validated用于验证字段的值
+ // @RequestBody 只能Post请求且 content-type=>application/json
+ @SneakyThrows
+ @PostMapping("/login")
+ public ApiResult login(@Validated @RequestBody LoginModel model) {
+ Thread.sleep(5);
+ final LoginUser user = userService.login(model.getUsername(), model.getPassword());
+
+ return ApiResult.success(user);
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/dao/LoginUserDao.java b/driver/src/main/java/xyz/longicorn/driver/dao/LoginUserDao.java
new file mode 100644
index 0000000..d1362f8
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/dao/LoginUserDao.java
@@ -0,0 +1,77 @@
+package xyz.longicorn.driver.dao;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+import xyz.longicorn.driver.pojo.LoginUser;
+
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class LoginUserDao {
+ private final String REDIS_PREFIX = "driver:user:token:";
+ private final RedisTemplate redisTemplate;
+
+ public LoginUserDao(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ private String buildTokenKey(String token) {
+ return REDIS_PREFIX + token;
+ }
+
+ public void refreshToken(String token) {
+ refreshToken(token, 1800);
+ }
+
+ public void refreshToken(String token, long timeout) {
+ redisTemplate.expire(buildTokenKey(token), timeout, TimeUnit.SECONDS);
+ }
+
+ public LoginUser save(LoginUser user) {
+ return save(user, 1800);
+ }
+
+ public LoginUser save(LoginUser user, long timeout) {
+ //更改在redis里面查看key编码问题
+ RedisSerializer redisSerializer = new StringRedisSerializer();
+ redisTemplate.setKeySerializer(redisSerializer);
+ ValueOperations vo = redisTemplate.opsForValue();
+ try {
+ String userJson = (new ObjectMapper()).writeValueAsString(user);
+ vo.set(buildTokenKey(user.getToken()), userJson, timeout, TimeUnit.SECONDS);//设置key并且设置有效时间
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ return user;
+ }
+
+ public LoginUser get(String token) {
+ ValueOperations vo = redisTemplate.opsForValue();
+ final Object o = vo.get(buildTokenKey(token));
+ if (null != o) {
+ try {
+ return (new ObjectMapper()).readValue(o.toString(), LoginUser.class);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ public boolean exists(String token) {
+ return redisTemplate.hasKey(buildTokenKey(token));
+ }
+
+ void deleteByToken(String token) {
+ redisTemplate.delete(buildTokenKey(token));
+ }
+
+ void delete(LoginUser user) {
+ deleteByToken(user.getToken());
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/dao/UserInfoMapper.java b/driver/src/main/java/xyz/longicorn/driver/dao/UserInfoMapper.java
new file mode 100644
index 0000000..cc50c70
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/dao/UserInfoMapper.java
@@ -0,0 +1,9 @@
+package xyz.longicorn.driver.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import xyz.longicorn.driver.pojo.UserInfo;
+
+@Mapper
+public interface UserInfoMapper extends BaseMapper {
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java b/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java
index 2002c5f..4e9b25e 100644
--- a/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java
+++ b/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java
@@ -67,8 +67,8 @@ public class FileItem {
.setType(f.getType())
// .setPath(f.getPath())
// .setThumb(f.getPath())
- .setPath("http://localhost:8080/preview?hash=" + f.getHash())
- .setThumb("http://localhost:8080/thumb?hash=" + f.getHash())
+ .setPath("http://localhost:8080/picture/preview?hash=" + f.getHash())
+ .setThumb("http://localhost:8080/picture/thumb?hash=" + f.getHash())
.setUpdateTime(f.getUpdateTime());
}
}
diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/LoginModel.java b/driver/src/main/java/xyz/longicorn/driver/dto/LoginModel.java
new file mode 100644
index 0000000..2925ee6
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/dto/LoginModel.java
@@ -0,0 +1,15 @@
+package xyz.longicorn.driver.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class LoginModel {
+ @NotBlank(message = "用户名必须填写")
+ private String username;
+ @NotBlank(message = "密码必须填写")
+ private String password;
+ // 验证码
+ private String code;
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/UserInfoDto.java b/driver/src/main/java/xyz/longicorn/driver/dto/UserInfoDto.java
new file mode 100644
index 0000000..5627830
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/dto/UserInfoDto.java
@@ -0,0 +1,4 @@
+package xyz.longicorn.driver.dto;
+
+public class UserInfoDto {
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/LoginUser.java b/driver/src/main/java/xyz/longicorn/driver/pojo/LoginUser.java
new file mode 100644
index 0000000..8d77e9e
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/pojo/LoginUser.java
@@ -0,0 +1,28 @@
+package xyz.longicorn.driver.pojo;
+
+
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.redis.core.RedisHash;
+import org.springframework.data.redis.core.index.Indexed;
+
+import java.util.Set;
+
+@Data
+@RedisHash(value = "driver_login_user", timeToLive = 3600) // 保持名称及有效期
+public class LoginUser {
+ @Id
+ private String token;
+ @Indexed
+ private String account;
+ private UserInfo userInfo;
+
+ /**
+ * 用户权限
+ */
+ private Set permissions;
+ /**
+ * 用户角色
+ */
+ private Set roles;
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/ShareInfo.java b/driver/src/main/java/xyz/longicorn/driver/pojo/ShareInfo.java
new file mode 100644
index 0000000..d2231bb
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/pojo/ShareInfo.java
@@ -0,0 +1,30 @@
+package xyz.longicorn.driver.pojo;
+
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+@Data
+@ToString
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+public class ShareInfo {
+ @TableId
+ private String id;
+ private String title;
+ private Integer uid;
+ private Long fileId;
+ private Integer type;
+ private String password;
+ private Integer live;
+ private Date createTime;
+ private Date updateTime;
+ private Integer status;
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/UserInfo.java b/driver/src/main/java/xyz/longicorn/driver/pojo/UserInfo.java
new file mode 100644
index 0000000..9189552
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/pojo/UserInfo.java
@@ -0,0 +1,33 @@
+package xyz.longicorn.driver.pojo;
+
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+@Data
+@ToString
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+public class UserInfo {
+
+ private Integer id;
+ private String nickname;
+ private String email;
+ private String account;
+ private String password;
+ private String salt;
+ private String avatar;
+ private Integer sex;
+ private String lastIp;
+ private Date lastLogin;
+ private Date createTime;
+ private Date updateTime;
+ private Integer status;
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/enums/Category.java b/driver/src/main/java/xyz/longicorn/driver/pojo/enums/Category.java
new file mode 100644
index 0000000..3ad8827
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/pojo/enums/Category.java
@@ -0,0 +1,21 @@
+package xyz.longicorn.driver.pojo.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+/**
+ * 文件的分类
+ */
+public enum Category {
+ Image(1, "图片"), Document(2, "文档"),
+ Video(3, "视频"), Audio(4, "音频"),
+ Other(5, "其他");
+
+ @EnumValue
+ private final int value;
+ private final String name;
+
+ Category(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/service/UserService.java b/driver/src/main/java/xyz/longicorn/driver/service/UserService.java
new file mode 100644
index 0000000..858e3d5
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/service/UserService.java
@@ -0,0 +1,53 @@
+package xyz.longicorn.driver.service;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.util.DigestUtils;
+import org.springframework.util.StringUtils;
+import xyz.longicorn.driver.config.BizException;
+import xyz.longicorn.driver.dao.LoginUserDao;
+import xyz.longicorn.driver.dao.UserInfoMapper;
+import xyz.longicorn.driver.pojo.LoginUser;
+import xyz.longicorn.driver.pojo.UserInfo;
+
+import javax.annotation.Resource;
+import java.util.UUID;
+
+@Service
+public class UserService extends ServiceImpl {
+ @Resource
+ private LoginUserDao loginUserDao;
+
+ /**
+ * 使用用户名和密码登录
+ *
+ * @param account
+ * @param password
+ * @return
+ */
+ public LoginUser login(String account, String password) {
+ // 查询数据条件
+ QueryWrapper q = new QueryWrapper();
+ // 只能根据账号查询数据
+ q.eq("account", account);
+ q.last("limit 1");
+ UserInfo userInfo = baseMapper.selectOne(q);
+ //
+ if (userInfo == null) throw BizException.create("用户名不正确");
+ // 获取密码并验证
+ String checkPassword = password + (StringUtils.hasLength(userInfo.getSalt()) ? userInfo.getSalt() : "");
+ checkPassword = DigestUtils.md5DigestAsHex(checkPassword.getBytes()); // 生成用于判断的密码
+
+ if (!checkPassword.equals(userInfo.getPassword())) throw BizException.create("登录密码不正确");
+ // 将登录数据保存到redis 用户后续判断
+ LoginUser user = new LoginUser();
+ user.setAccount(account);
+ // 生成接口需要的token
+ user.setToken(IdUtil.fastSimpleUUID()); // 可以使用jwt生成token
+ loginUserDao.save(user); // 保存用户登录信息到redis
+ user.setUserInfo(userInfo);
+ return user;
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/shiro/AuthFilter.java b/driver/src/main/java/xyz/longicorn/driver/shiro/AuthFilter.java
new file mode 100644
index 0000000..730c233
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/shiro/AuthFilter.java
@@ -0,0 +1,162 @@
+package xyz.longicorn.driver.shiro;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMethod;
+import xyz.longicorn.driver.dao.LoginUserDao;
+import xyz.longicorn.driver.pojo.LoginUser;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Slf4j
+public class AuthFilter extends BasicHttpAuthenticationFilter {
+
+ private LoginUserDao loginUserDao;
+
+ // 构造把需要的资源 由其他对象传输过来
+ public AuthFilter(LoginUserDao loginUserDao){
+ this.loginUserDao = loginUserDao;
+ }
+
+
+ private static final String AUTH_TOKEN_HEADER = "Authorization";
+
+ //判断是否允许通过
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ log.debug("判断是否允许通过");
+ try {
+ // 执行登录 也可以重写此方法 自行实现登录
+ return executeLogin(request, response);
+ } catch (Exception e) {
+ log.error("执行允许通过异常:" + e.getMessage(), e);
+ //responseError(response, "auth check fail");
+ return false;
+ }
+ }
+
+
+ /**
+ * 是否需要进行登录请求(false将不会继续后续操纵)
+ * 简单的判断是否存在对应的凭证
+ *
+ * @param request
+ * @param response
+ * @return
+ */
+ @Override
+ protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
+ return ((HttpServletRequest) request).getHeader(AUTH_TOKEN_HEADER) != null;
+ }
+
+ /**
+ * 读取请求的token头信息
+ * 创建shiro token
+ *
+ * @param request
+ * @param response
+ * @return
+ */
+ @Override
+ protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
+ HttpServletRequest req = (HttpServletRequest) request;
+ String token = req.getHeader(AUTHORIZATION_HEADER); //
+ if (StringUtils.hasLength(token)) {
+ return new SimpleHeaderToken(token);
+ }
+ return null;
+ }
+
+ /**
+ * isAccessAllowed为false时调用,验证失败
+ *
+ * @param request
+ * @param response
+ * @return
+ * @throws Exception
+ */
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+ this.sendChallenge(request, response);
+ responseError(response, "login token check failure!");
+ return false;
+ }
+
+ /**
+ * 验证成功调用 可以将一些信息放入内存,以及更新token有效期
+ *
+ * @param token
+ * @param subject
+ * @param request
+ * @param response
+ * @return
+ * @throws Exception
+ */
+ @Override
+ protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
+ ServletRequest request, ServletResponse response) throws Exception {
+ // 获取token
+ String tokenValue = (String)token.getPrincipal();
+ // 通过token 获取登录用户信息
+ final LoginUser loginUser = loginUserDao.get(tokenValue);
+ if(null != loginUser){
+ // 更新token有效期
+ loginUserDao.refreshToken(tokenValue);
+ return true;
+ }
+ return false;
+
+ }
+
+ // 前置判断 - 过滤的主要流程
+ // 过滤的入口 如果返回false 表示不需要过滤 不进行后续代码执行
+ @Override
+ protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
+ // 针对 options 直接通过
+ if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
+ ((HttpServletResponse) response).setStatus(HttpStatus.OK.value());
+ setCors(response); // 直接允许跨域
+ return false;
+ }
+ //判断用户是否想要登入 -- 判断header中有没有 token
+ if (!isLoginAttempt(request, response)) {
+ responseError(response, "verify token failure(没有token)");
+ return false;
+ }
+ // 如果只是简单判断 可以不用调用父级的preHandle 当然也就不需要重写其他的方法
+ return super.preHandle(request, response);
+ }
+
+ private void setCors(ServletResponse response) {
+ HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+ httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
+ httpServletResponse.addHeader("Access-Control-Allow-Methods", "*");
+ httpServletResponse.addHeader("Access-Control-Allow-Headers", "*");
+ }
+
+ private void responseError(ServletResponse response, Object msg) {
+ setCors(response);
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ httpResponse.setStatus(401);
+ httpResponse.setCharacterEncoding("UTF-8");
+ httpResponse.setContentType("application/json;charset=UTF-8");
+ try {
+ String rj = msg instanceof String ? "{\"code\":401,\"message\":\"" + (String) msg + "\"}" : new ObjectMapper().writeValueAsString(msg);
+ httpResponse.getWriter().append(rj);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/shiro/ShiroConfig.java b/driver/src/main/java/xyz/longicorn/driver/shiro/ShiroConfig.java
new file mode 100644
index 0000000..318f871
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/shiro/ShiroConfig.java
@@ -0,0 +1,93 @@
+package xyz.longicorn.driver.shiro;
+
+import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
+import org.apache.shiro.mgt.DefaultSubjectDAO;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import xyz.longicorn.driver.dao.LoginUserDao;
+
+import javax.annotation.Resource;
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Configuration
+public class ShiroConfig {
+ @Resource
+ private LoginUserDao loginUserDao;
+
+ // 配置哪些资源过滤
+ //ShiroFilter过滤所有请求
+ @Bean
+ public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
+
+ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+
+ Map filterMap = new LinkedHashMap<>(); // 需要有序
+ filterMap.put("auth", new AuthFilter(loginUserDao)); // 设置验证过滤器
+ shiroFilterFactoryBean.setFilters(filterMap);
+
+ //给ShiroFilter配置安全管理器
+ shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
+
+ //配置系统公共资源 不要用HashMap来创建Map,资源的配置有先后顺序
+ Map map = new LinkedHashMap<>();
+ /**
+ * anon---------------org.apache.shiro.web.filter.authc.AnonymousFilter 没有参数,表示可以匿名使用。
+ * authc--------------org.apache.shiro.web.filter.authc.FormAuthenticationFilter 表示需要认证(登录)才能使用,没有参数
+ * authcBasic---------org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter 没有参数表示httpBasic认证
+ * logout-------------org.apache.shiro.web.filter.authc.LogoutFilter
+ * noSessionCreation--org.apache.shiro.web.filter.session.NoSessionCreationFilter
+ * perms--------------org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter 参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
+ * port---------------org.apache.shiro.web.filter.authz.PortFilter port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。
+ * rest---------------org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter 根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
+ * roles--------------org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
+ * ssl----------------org.apache.shiro.web.filter.authz.SslFilter 没有参数,表示安全的url请求,协议为https
+ * user---------------org.apache.shiro.web.filter.authz.UserFilter 没有参数表示必须存在用户,当登入操作时不做检查
+ */
+ //匿名资源 一定是在受限资源上面
+ // 前面时资源的路径 后面是该资源的过滤器
+ map.put("/druid/**", "anon");
+ map.put("/api/user/login", "anon");
+ map.put("/api/user/reg", "anon");
+ map.put("/api/user/forget", "anon");
+ map.put("/api/user/reset", "anon");
+ map.put("/swagger**", "anon"); //
+ map.put("/swagger-resources/**","anon");
+ map.put("/v2/api-docs","anon");
+ map.put("/picture/**","anon");
+ //受限资源需要认证和授权
+ map.put("/**", "auth");
+ //filterChainDefinitions的配置顺序为自上而下,以最上面的为准
+ shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
+
+ //身份认证失败,则跳转到登录页面的配置 没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,
+ // 不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
+// shiroFilterFactoryBean.setLoginUrl("");
+ //登录成功默认跳转页面,不配置则跳转至”/”。
+ // 如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。
+// shiroFilterFactoryBean.setSuccessUrl("");
+ //没有权限默认跳转的页面
+// shiroFilterFactoryBean.setUnauthorizedUrl("");
+ return shiroFilterFactoryBean;
+ }
+
+
+ @Bean
+ public DefaultWebSecurityManager defaultWebSecurityManager(UserRealm userRealm) {
+ //设置自定义Realm
+ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+ securityManager.setRealm(userRealm);
+ //关闭shiro自带的session
+ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
+ DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
+ defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
+ subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
+ securityManager.setSubjectDAO(subjectDAO);
+ return securityManager;
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/shiro/SimpleHeaderToken.java b/driver/src/main/java/xyz/longicorn/driver/shiro/SimpleHeaderToken.java
new file mode 100644
index 0000000..3a1f23f
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/shiro/SimpleHeaderToken.java
@@ -0,0 +1,24 @@
+package xyz.longicorn.driver.shiro;
+
+import org.apache.shiro.authc.AuthenticationToken;
+
+/**
+ * 简单的token
+ */
+public class SimpleHeaderToken implements AuthenticationToken {
+ private String token;
+
+ public SimpleHeaderToken(String token) {
+ this.token = token;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return token;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return token;
+ }
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/config/UserRealm.java b/driver/src/main/java/xyz/longicorn/driver/shiro/UserRealm.java
similarity index 73%
rename from driver/src/main/java/xyz/longicorn/driver/config/UserRealm.java
rename to driver/src/main/java/xyz/longicorn/driver/shiro/UserRealm.java
index 686c7b4..4d7736b 100644
--- a/driver/src/main/java/xyz/longicorn/driver/config/UserRealm.java
+++ b/driver/src/main/java/xyz/longicorn/driver/shiro/UserRealm.java
@@ -1,4 +1,4 @@
-package xyz.longicorn.driver.config;
+package xyz.longicorn.driver.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
@@ -9,13 +9,24 @@ import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
+import xyz.longicorn.driver.dao.LoginUserDao;
+import xyz.longicorn.driver.pojo.LoginUser;
+import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
@Component
public class UserRealm extends AuthorizingRealm {
+@Resource
+ private LoginUserDao loginUserDao;
+ // 判断是否支持对应请求token
+ @Override
+ public boolean supports(AuthenticationToken token) {
+ return token != null && token instanceof SimpleHeaderToken;
+ }
+
// 处理授权 获取凭证对该凭证赋权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
@@ -25,9 +36,13 @@ public class UserRealm extends AuthorizingRealm {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set roleSet = new HashSet<>(); // 角色列表
+ roleSet.add("user");
+ roleSet.add("vip");
info.setRoles(roleSet);
Set permsSet = new HashSet<>(); // 权限列表
+ permsSet.add("query-list");
+ permsSet.add("upload-file");
info.setStringPermissions(permsSet);
return info;
}
@@ -38,7 +53,8 @@ public class UserRealm extends AuthorizingRealm {
throws AuthenticationException {
String credentials = (String) authenticationToken.getCredentials(); // 获取凭证
System.out.println("用户凭证:" + credentials);
- //TODO 完成token的验证 返回数据库信息
+ //TODO 完成token的验证(是否有效) 返回数据库信息
+
return new SimpleAuthenticationInfo(credentials, credentials, getName());
}
}
diff --git a/driver/src/main/java/xyz/longicorn/driver/util/JWTUtil.java b/driver/src/main/java/xyz/longicorn/driver/util/JWTUtil.java
new file mode 100644
index 0000000..13dfde9
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/util/JWTUtil.java
@@ -0,0 +1,98 @@
+package xyz.longicorn.driver.util;
+
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTCreationException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class JWTUtil {
+
+ //这里的token属性配置最好写在配置文件中,这里为了方便直接写成静态属性
+ public static final long EXPIRE_TIME = 60 * 60 * 1000;//token到期时间60分钟,毫秒为单位
+ public static final long REFRESH_EXPIRE_TIME = 30 * 60;//RefreshToken到期时间为30分钟,秒为单位
+ private static final String TOKEN_SECRET = "ljdyaidarking**3nkjnj??"; //密钥盐
+ /**
+ * 发行人
+ */
+ private static final String ISSUER = "DK";
+
+ /**
+ * 生成token
+ *
+ * @param account
+ * @param currentTime
+ * @return
+ */
+ public static String create(String account, Long currentTime) {
+
+ String token = null;
+ try {
+ Date expireAt = new Date(currentTime + EXPIRE_TIME);
+ token = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim("account", account)//存放数据
+ .withClaim("currentTime", currentTime)
+ .withExpiresAt(expireAt)//过期时间
+ .sign(Algorithm.HMAC256(TOKEN_SECRET));
+ } catch (IllegalArgumentException | JWTCreationException je) {
+
+ }
+ return token;
+ }
+
+
+ /**
+ * @param : [token]
+ * @return : java.lang.Boolean
+ * @throws :
+ * @Description :token验证
+ * @author : lj
+ * @date : 2020-1-31 22:59
+ */
+ public static Boolean verify(String token) throws Exception {
+ try {
+ JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET))
+ .withIssuer(ISSUER).build();//创建token验证器
+ DecodedJWT decodedJWT = jwtVerifier.verify(token);
+ System.out.println("认证通过:");
+ System.out.println("account: " + decodedJWT.getClaim("account").asString());
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ System.out.println("过期时间:" + sdf.format(decodedJWT.getExpiresAt()));
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+
+ public static String getAccount(HttpServletRequest request) {
+ String token = request.getHeader("token");
+ return getAccount(token);
+ }
+
+ public static String getAccount(String token) {
+ if (token == null) return null;
+ try {
+ DecodedJWT decodedJWT = JWT.decode(token);
+ return decodedJWT.getClaim("account").asString();
+ } catch (JWTCreationException e) {
+ return null;
+ }
+ }
+
+ public static Long getCurrentTime(String token) {
+ try {
+ DecodedJWT decodedJWT = JWT.decode(token);
+ return decodedJWT.getClaim("currentTime").asLong();
+ } catch (JWTCreationException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/driver/src/main/java/xyz/longicorn/driver/util/RedisUtil.java b/driver/src/main/java/xyz/longicorn/driver/util/RedisUtil.java
new file mode 100644
index 0000000..328da7a
--- /dev/null
+++ b/driver/src/main/java/xyz/longicorn/driver/util/RedisUtil.java
@@ -0,0 +1,8 @@
+package xyz.longicorn.driver.util;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class RedisUtil {
+
+}
diff --git a/driver/src/main/resources/db.sql b/driver/src/main/resources/db.sql
index 04c52e3..caa8b6d 100644
--- a/driver/src/main/resources/db.sql
+++ b/driver/src/main/resources/db.sql
@@ -1,7 +1,7 @@
-- 编号、用户编号、目录名称、上级目录编号、目录路径、创建时间、状态
create table folder_info
(
- id bigint(20) primary key auto_increment,
+ id bigint(20) UNSIGNED primary key auto_increment,
uid int(10) null default 1,
name varchar(20) not null,
parent_id bigint(20) null default 0 comment '上级目录编号,0表示根目录',
@@ -17,17 +17,17 @@ create table folder_info
# 编号、用户编号、文件名、目录编号 、类型、大小、位置、创建时间、状态、hash
create table file_info
(
- id bigint(20) not null primary key auto_increment,
- uid int(10) not null,
- name varchar(50) not null,
- hash varchar(32) not null comment '文件MD5特征码',
- folder_id bigint(20) null default 0 comment '所在目录的编号,0表示根目录',
- type varchar(5) null,
- size int null default 0,
- path varchar(500) not null comment '文件的物理存储位置,可以是本地路径也可以是一个网址', -- file://d:/a/b/c.txt http://
- create_time datetime default current_timestamp,
+ id bigint(20) UNSIGNED not null primary key auto_increment,
+ uid int(10) not null,
+ name varchar(50) not null,
+ hash varchar(32) not null comment '文件MD5特征码',
+ folder_id bigint(20) null default 0 comment '所在目录的编号,0表示根目录',
+ type varchar(5) null,
+ size int null default 0,
+ path varchar(500) not null comment '文件的物理存储位置,可以是本地路径也可以是一个网址', -- file://d:/a/b/c.txt http://
+ create_time datetime default current_timestamp,
update_time datetime on update current_timestamp,
- status tinyint(1) default 1,
+ status tinyint(1) default 1,
index ix_file_name (name)
);
-- 编号、分享名称、用户编号、分享的数据编号、分类类型(file|folder)、提取码、分享有效期、状态
@@ -45,3 +45,19 @@ create table share_info
status tinyint(1) default 1,
index ix_file_name (title)
);
+CREATE TABLE user_info
+(
+ id int(10) UNSIGNED NOT NULL,
+ nickname varchar(60) NOT NULL COMMENT '昵称',
+ email varchar(60) DEFAULT '邮箱',
+ account varchar(60) NOT NULL COMMENT '登录账号',
+ password varchar(32) NOT NULL COMMENT '登录密码',
+ salt varchar(10) COMMENT '登录密码混淆字符',
+ avatar varchar(255) COMMENT '登录密码',
+ sex tinyint(1) default 0 comment '0:未知 1男 2女',
+ last_login datetime null,
+ last_ip varchar(50) null,
+ create_time datetime default current_timestamp,
+ update_time datetime on update current_timestamp,
+ status tinyint(1) default 1
+);
\ No newline at end of file
diff --git a/web/package-lock.json b/web/package-lock.json
index 4b5f29f..b8be418 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -18,7 +18,8 @@
"vue": "^3.2.25",
"vue-router": "^4.0.15",
"vue-simple-context-menu": "^4.0.2",
- "vue-upload-component": "^2.8.22"
+ "vue-upload-component": "^2.8.22",
+ "vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.1",
@@ -1213,6 +1214,17 @@
"version": "2.8.22",
"resolved": "https://registry.npmmirror.com/vue-upload-component/-/vue-upload-component-2.8.22.tgz",
"integrity": "sha512-AJpETqiZrgqs8bwJQpWTFrRg3i6s7cUodRRZVnb1f94Jvpd0YYfzGY4zluBqPmssNSkUaYu7EteXaK8aW17Osw=="
+ },
+ "node_modules/vuex": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz",
+ "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.0.0-beta.11"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.2"
+ }
}
},
"dependencies": {
@@ -2020,6 +2032,14 @@
"version": "2.8.22",
"resolved": "https://registry.npmmirror.com/vue-upload-component/-/vue-upload-component-2.8.22.tgz",
"integrity": "sha512-AJpETqiZrgqs8bwJQpWTFrRg3i6s7cUodRRZVnb1f94Jvpd0YYfzGY4zluBqPmssNSkUaYu7EteXaK8aW17Osw=="
+ },
+ "vuex": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz",
+ "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+ "requires": {
+ "@vue/devtools-api": "^6.0.0-beta.11"
+ }
}
}
}
diff --git a/web/package.json b/web/package.json
index aee4bfd..93ddfb6 100644
--- a/web/package.json
+++ b/web/package.json
@@ -18,7 +18,8 @@
"vue": "^3.2.25",
"vue-router": "^4.0.15",
"vue-simple-context-menu": "^4.0.2",
- "vue-upload-component": "^2.8.22"
+ "vue-upload-component": "^2.8.22",
+ "vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.1",
diff --git a/web/src/components/FileBlockItem.vue b/web/src/components/FileBlockItem.vue
index 44eaa71..9980754 100644
--- a/web/src/components/FileBlockItem.vue
+++ b/web/src/components/FileBlockItem.vue
@@ -9,13 +9,20 @@
file.type == 'folder' ? formatDate(file.createTime) : formatSize(file.size)
}}
+